< Summary

Line coverage
32%
Covered lines: 111
Uncovered lines: 235
Coverable lines: 346
Total lines: 11439
Line coverage: 32%
Branch coverage
31%
Covered branches: 81
Total branches: 255
Branch coverage: 31.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/.nuget/packages/fastexpressioncompiler.internal.src/5.3.3/contentFiles/cs/net8.0/FastExpressionCompiler.Internal/FastExpressionCompiler.cs

#LineLine coverage
 1#pragma warning disable
 2// <auto-generated/>
 3/*
 4The MIT License (MIT)
 5
 6Copyright (c) 2016-2025 Maksim Volkau
 7
 8Permission is hereby granted, free of charge, to any person obtaining a copy
 9of this software and associated documentation files (the "Software"), to deal
 10in the Software without restriction, including without limitation the rights
 11to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 12copies of the Software, and to permit persons to whom the Software is
 13furnished to do so, subject to the following conditions:
 14
 15The above copyright notice and this permission notice shall be included
 16all copies or substantial portions of the Software.
 17
 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 21AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 22LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 23OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 24THE SOFTWARE.
 25*/
 26
 27// ReSharper disable CoVariantArrayConversion
 28#nullable disable
 29
 30// #define LIGHT_EXPRESSION
 31
 32#if DEBUG && NET6_0_OR_GREATER
 33#define DEBUG_INFO_LOCAL_VARIABLE_USAGE
 34#define DEMIT
 35#define INTERPRETATION_DIAGNOSTICS
 36#endif
 37
 38#if LIGHT_EXPRESSION
 39#define SUPPORTS_ARGUMENT_PROVIDER
 40#endif
 41
 42#if LIGHT_EXPRESSION
 43namespace FastExpressionCompiler.LightExpression
 44{
 45    using static FastExpressionCompiler.LightExpression.Expression;
 46    using PE = FastExpressionCompiler.LightExpression.ParameterExpression;
 47    using FastExpressionCompiler.LightExpression.ImTools;
 48    using FastExpressionCompiler.LightExpression.ILDecoder;
 49    using static FastExpressionCompiler.LightExpression.ImTools.SmallMap;
 50#else
 51namespace FastExpressionCompiler
 52{
 53    using static System.Linq.Expressions.Expression;
 54    using PE = System.Linq.Expressions.ParameterExpression;
 55    using FastExpressionCompiler.ImTools;
 56    using FastExpressionCompiler.ILDecoder;
 57    using static FastExpressionCompiler.ImTools.SmallMap;
 58#endif
 59    using System;
 60    using System.Collections;
 61    using System.Collections.Generic;
 62    using System.Linq;
 63    using System.Linq.Expressions;
 64    using System.Reflection;
 65    using System.Reflection.Emit;
 66    using System.Threading;
 67    using System.Text;
 68    using System.Runtime.CompilerServices;
 69    using System.Runtime.InteropServices;
 70    using System.Diagnostics;
 71    using System.Diagnostics.CodeAnalysis;
 72    using static System.Environment;
 73    using static CodePrinter;
 74
 75    /// <summary>The flags for the compiler</summary>
 76    [Flags]
 77    internal enum CompilerFlags : byte
 78    {
 79        /// <summary>The default flags: Invocation lambda is inlined, no debug info</summary>
 80        Default = 0,
 81        /// <summary>Prevents the inlining of the lambda in the Invocation expression to optimize for the multiple same 
 82        NoInvocationLambdaInlining = 1,
 83        /// <summary>Adds the Expression, ExpressionString, and CSharpString to the delegate closure for the debugging i
 84        EnableDelegateDebugInfo = 1 << 1,
 85        /// <summary>When the flag is set then instead of the returning `null` the specific exception is thrown*346</sum
 86        ThrowOnNotSupportedExpression = 1 << 2,
 87        /// <summary>Will try to Interpret arithmetic, logical, comparison expressions for the primitive types,
 88        /// and emit the IL the result only instead of the whole computation.</summary>
 89        DisableInterpreter = 1 << 4
 90    }
 91
 92    /// <summary>FEC Not Supported exception</summary>
 93    internal sealed class NotSupportedExpressionException : InvalidOperationException
 94    {
 95        /// <summary>The reason</summary>
 96        public readonly ExpressionCompiler.Result Reason;
 97        /// <summary>Constructor</summary>
 98        public NotSupportedExpressionException(ExpressionCompiler.Result reason) : base(reason.ToString()) => Reason = r
 99        /// <summary>Constructor</summary>
 100        public NotSupportedExpressionException(ExpressionCompiler.Result reason, string message) : base(reason + ": " + 
 101    }
 102
 103    /// <summary>The interface is implemented by the compiled delegate Target if `CompilerFlags.EnableDelegateDebugInfo`
 104    internal interface IDelegateDebugInfo
 105    {
 106        /// <summary>The lambda expression object that was compiled to the delegate</summary>
 107        LambdaExpression Expression { get; }
 108
 109        /// <summary>Delegate IL op-codes</summary>
 110        ILInstruction[] ILInstructions { get; }
 111
 112        /// <summary>Enumerate any nested lambdas in the delegate</summary>
 113        [RequiresUnreferencedCode(Trimming.Message)]
 114        IEnumerable<IDelegateDebugInfo> EnumerateNestedLambdas();
 115    }
 116
 117    /// <summary>Compiles expression to delegate ~20 times faster than Expression.Compile.
 118    /// Partial to extend with your things when used as source file.</summary>
 119    // ReSharper disable once PartialTypeWithSinglePart
 120    [RequiresUnreferencedCode(Trimming.Message)]
 121    internal static partial class ExpressionCompiler
 122    {
 123        #region Expression.CompileFast overloads for Delegate, Func, and Action
 124
 125        /// <summary>Compiles lambda expression to TDelegate type. Use ifFastFailedReturnNull parameter to Not fallback 
 126        public static TDelegate CompileFast<TDelegate>(this LambdaExpression lambdaExpr,
 127            bool ifFastFailedReturnNull = false, CompilerFlags flags = CompilerFlags.Default) where TDelegate : class =>
 128            (TDelegate)(TryCompileBoundToFirstClosureParam(
 129                typeof(TDelegate) == typeof(Delegate) ? lambdaExpr.Type : typeof(TDelegate), lambdaExpr.Body,
 130#if LIGHT_EXPRESSION
 131                lambdaExpr,
 132#else
 133                lambdaExpr.Parameters,
 134#endif
 135                lambdaExpr.ReturnType, flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys()));
 136
 137        /// <summary>Compiles a static method to the passed IL Generator.
 138        /// Could be used as alternative for `CompileToMethod` like this <code><![CDATA[funcExpr.CompileFastToIL(methodB
 139        /// Check `IssueTests.Issue179_Add_something_like_LambdaExpression_CompileToMethod.cs` for example.</summary>
 140        public static bool CompileFastToIL(this LambdaExpression lambdaExpr, ILGenerator il, CompilerFlags flags = Compi
 141        {
 142            if ((flags & CompilerFlags.EnableDelegateDebugInfo) != 0)
 143                throw new NotSupportedException("The `CompilerFlags.EnableDelegateDebugInfo` is not supported because th
 144
 145#if LIGHT_EXPRESSION
 146            var paramExprs = lambdaExpr;
 147#else
 148            var paramExprs = lambdaExpr.Parameters;
 149#endif
 150            var bodyExpr = lambdaExpr.Body;
 151
 152            var closureInfo = new ClosureInfo(ClosureStatus.ShouldBeStaticMethod);
 153            var nestedLambdas = new SmallList<NestedLambdaInfo>();
 154            if (!TryCollectBoundConstants(ref closureInfo, bodyExpr, paramExprs, null, ref nestedLambdas, flags))
 155                return false;
 156
 157            if ((closureInfo.Status & ClosureStatus.HasClosure) != 0)
 158                return false;
 159
 160            var parent = lambdaExpr.ReturnType == typeof(void) ? ParentFlags.IgnoreResult : ParentFlags.LambdaCall;
 161            if (!EmittingVisitor.TryEmit(bodyExpr, paramExprs, il, ref closureInfo, flags, parent))
 162                return false;
 163
 164            il.Demit(OpCodes.Ret);
 165            return true;
 166        }
 167
 168        /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Exp
 169        public static Delegate CompileFast(this LambdaExpression lambdaExpr, bool ifFastFailedReturnNull = false, Compil
 170            (Delegate)TryCompileBoundToFirstClosureParam(lambdaExpr.Type, lambdaExpr.Body,
 171#if LIGHT_EXPRESSION
 172            lambdaExpr,
 173#else
 174            lambdaExpr.Parameters,
 175#endif
 176            lambdaExpr.ReturnType, flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 177
 178        /// <summary>Returns the System expression itself or convert the System expression into Light Expression</summar
 179        public static Expression<TDelegate> FromSysExpression<TDelegate>(this System.Linq.Expressions.Expression<TDelega
 180#if LIGHT_EXPRESSION
 181            lambdaExpr.ToLightExpression();
 182#else
 183            lambdaExpr;
 184#endif
 185
 186        /// <summary>Returns the System expression itself or convert the System expression into Light Expression</summar
 187        public static LambdaExpression FromSysExpression(this System.Linq.Expressions.LambdaExpression lambdaExpr) =>
 188#if LIGHT_EXPRESSION
 189            lambdaExpr.ToLightExpression();
 190#else
 191            lambdaExpr;
 192#endif
 193
 194        /// <summary>Unifies Compile for System.Linq.Expressions and FEC.LightExpression</summary>
 195        public static TDelegate CompileSys<TDelegate>(this Expression<TDelegate> lambdaExpr) where TDelegate : System.De
 196            lambdaExpr
 197#if LIGHT_EXPRESSION
 198            .ToLambdaExpression()
 199#endif
 200            .Compile();
 201
 202        /// <summary>Unifies Compile for System.Linq.Expressions and FEC.LightExpression</summary>
 203        public static Delegate CompileSys(this LambdaExpression lambdaExpr) =>
 204            lambdaExpr
 205#if LIGHT_EXPRESSION
 206            .ToLambdaExpression()
 207#endif
 208            .Compile();
 209
 210        /// <summary>Compiles lambda expression to TDelegate type. Use ifFastFailedReturnNull parameter to Not fallback 
 211        public static TDelegate CompileFast<TDelegate>(this Expression<TDelegate> lambdaExpr, bool ifFastFailedReturnNul
 212            CompilerFlags flags = CompilerFlags.Default) where TDelegate : System.Delegate =>
 213            ((LambdaExpression)lambdaExpr).CompileFast<TDelegate>(ifFastFailedReturnNull, flags);
 214
 215        /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Exp
 216        public static Func<R> CompileFast<R>(this Expression<Func<R>> lambdaExpr, bool ifFastFailedReturnNull = false,
 217            CompilerFlags flags = CompilerFlags.Default) =>
 218            (Func<R>)TryCompileBoundToFirstClosureParam(typeof(Func<R>), lambdaExpr.Body,
 219#if LIGHT_EXPRESSION
 220                lambdaExpr,
 221#else
 222                lambdaExpr.Parameters,
 223#endif
 224                typeof(R), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 225
 226        /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Exp
 227        public static Func<T1, R> CompileFast<T1, R>(this Expression<Func<T1, R>> lambdaExpr,
 228            bool ifFastFailedReturnNull = false, CompilerFlags flags = CompilerFlags.Default) =>
 229            (Func<T1, R>)TryCompileBoundToFirstClosureParam(typeof(Func<T1, R>), lambdaExpr.Body,
 230#if LIGHT_EXPRESSION
 231                lambdaExpr,
 232#else
 233                lambdaExpr.Parameters,
 234#endif
 235            typeof(R), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 236
 237        /// <summary>Compiles lambda expression to TDelegate type. Use ifFastFailedReturnNull parameter to Not fallback 
 238        public static Func<T1, T2, R> CompileFast<T1, T2, R>(this Expression<Func<T1, T2, R>> lambdaExpr,
 239            bool ifFastFailedReturnNull = false, CompilerFlags flags = CompilerFlags.Default) =>
 240            (Func<T1, T2, R>)TryCompileBoundToFirstClosureParam(typeof(Func<T1, T2, R>), lambdaExpr.Body,
 241#if LIGHT_EXPRESSION
 242                lambdaExpr,
 243#else
 244                lambdaExpr.Parameters,
 245#endif
 246                typeof(R), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 247
 248        /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Exp
 249        public static Func<T1, T2, T3, R> CompileFast<T1, T2, T3, R>(
 250            this Expression<Func<T1, T2, T3, R>> lambdaExpr, bool ifFastFailedReturnNull = false, CompilerFlags flags = 
 251            (Func<T1, T2, T3, R>)TryCompileBoundToFirstClosureParam(typeof(Func<T1, T2, T3, R>), lambdaExpr.Body,
 252#if LIGHT_EXPRESSION
 253                lambdaExpr,
 254#else
 255                lambdaExpr.Parameters,
 256#endif
 257            typeof(R), flags)
 258            ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 259
 260        /// <summary>Compiles lambda expression to TDelegate type. Use ifFastFailedReturnNull parameter to Not fallback 
 261        public static Func<T1, T2, T3, T4, R> CompileFast<T1, T2, T3, T4, R>(
 262            this Expression<Func<T1, T2, T3, T4, R>> lambdaExpr, bool ifFastFailedReturnNull = false, CompilerFlags flag
 263            (Func<T1, T2, T3, T4, R>)TryCompileBoundToFirstClosureParam(typeof(Func<T1, T2, T3, T4, R>), lambdaExpr.Body
 264#if LIGHT_EXPRESSION
 265                lambdaExpr,
 266#else
 267                lambdaExpr.Parameters,
 268#endif
 269                typeof(R), flags)
 270            ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 271
 272        /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Exp
 273        public static Func<T1, T2, T3, T4, T5, R> CompileFast<T1, T2, T3, T4, T5, R>(
 274            this Expression<Func<T1, T2, T3, T4, T5, R>> lambdaExpr, bool ifFastFailedReturnNull = false, CompilerFlags 
 275            (Func<T1, T2, T3, T4, T5, R>)TryCompileBoundToFirstClosureParam(typeof(Func<T1, T2, T3, T4, T5, R>), lambdaE
 276#if LIGHT_EXPRESSION
 277                lambdaExpr,
 278#else
 279                lambdaExpr.Parameters,
 280#endif
 281                typeof(R), flags)
 282            ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 283
 284        /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Exp
 285        public static Func<T1, T2, T3, T4, T5, T6, R> CompileFast<T1, T2, T3, T4, T5, T6, R>(
 286            this Expression<Func<T1, T2, T3, T4, T5, T6, R>> lambdaExpr, bool ifFastFailedReturnNull = false, CompilerFl
 287            (Func<T1, T2, T3, T4, T5, T6, R>)TryCompileBoundToFirstClosureParam(typeof(Func<T1, T2, T3, T4, T5, T6, R>),
 288#if LIGHT_EXPRESSION
 289                lambdaExpr,
 290#else
 291                lambdaExpr.Parameters,
 292#endif
 293                typeof(R), flags)
 294            ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 295
 296        /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Exp
 297        public static Action CompileFast(this Expression<Action> lambdaExpr, bool ifFastFailedReturnNull = false, Compil
 298            (Action)TryCompileBoundToFirstClosureParam(typeof(Action), lambdaExpr.Body,
 299#if LIGHT_EXPRESSION
 300                lambdaExpr,
 301#else
 302                lambdaExpr.Parameters,
 303#endif
 304            typeof(void), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 305
 306        /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Exp
 307        public static Action<T1> CompileFast<T1>(this Expression<Action<T1>> lambdaExpr,
 308            bool ifFastFailedReturnNull = false, CompilerFlags flags = CompilerFlags.Default) =>
 309            (Action<T1>)TryCompileBoundToFirstClosureParam(typeof(Action<T1>), lambdaExpr.Body,
 310#if LIGHT_EXPRESSION
 311                lambdaExpr,
 312#else
 313                lambdaExpr.Parameters,
 314#endif
 315            typeof(void), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 316
 317        /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Exp
 318        public static Action<T1, T2> CompileFast<T1, T2>(this Expression<Action<T1, T2>> lambdaExpr,
 319            bool ifFastFailedReturnNull = false, CompilerFlags flags = CompilerFlags.Default) =>
 320            (Action<T1, T2>)TryCompileBoundToFirstClosureParam(typeof(Action<T1, T2>), lambdaExpr.Body,
 321#if LIGHT_EXPRESSION
 322                lambdaExpr,
 323#else
 324                lambdaExpr.Parameters,
 325#endif
 326            typeof(void), flags) ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 327
 328        /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Exp
 329        public static Action<T1, T2, T3> CompileFast<T1, T2, T3>(this Expression<Action<T1, T2, T3>> lambdaExpr,
 330            bool ifFastFailedReturnNull = false, CompilerFlags flags = CompilerFlags.Default) =>
 331            (Action<T1, T2, T3>)TryCompileBoundToFirstClosureParam(typeof(Action<T1, T2, T3>), lambdaExpr.Body,
 332#if LIGHT_EXPRESSION
 333                lambdaExpr,
 334#else
 335                lambdaExpr.Parameters,
 336#endif
 337                typeof(void), flags)
 338            ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 339
 340        /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Exp
 341        public static Action<T1, T2, T3, T4> CompileFast<T1, T2, T3, T4>(
 342            this Expression<Action<T1, T2, T3, T4>> lambdaExpr, bool ifFastFailedReturnNull = false, CompilerFlags flags
 343            (Action<T1, T2, T3, T4>)TryCompileBoundToFirstClosureParam(typeof(Action<T1, T2, T3, T4>), lambdaExpr.Body,
 344#if LIGHT_EXPRESSION
 345                lambdaExpr,
 346#else
 347                lambdaExpr.Parameters,
 348#endif
 349                typeof(void), flags)
 350            ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 351
 352        /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Exp
 353        public static Action<T1, T2, T3, T4, T5> CompileFast<T1, T2, T3, T4, T5>(
 354            this Expression<Action<T1, T2, T3, T4, T5>> lambdaExpr, bool ifFastFailedReturnNull = false, CompilerFlags f
 355            (Action<T1, T2, T3, T4, T5>)TryCompileBoundToFirstClosureParam(typeof(Action<T1, T2, T3, T4, T5>), lambdaExp
 356#if LIGHT_EXPRESSION
 357                lambdaExpr,
 358#else
 359                lambdaExpr.Parameters,
 360#endif
 361                typeof(void), flags)
 362            ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 363
 364        /// <summary>Compiles lambda expression to delegate. Use ifFastFailedReturnNull parameter to Not fallback to Exp
 365        public static Action<T1, T2, T3, T4, T5, T6> CompileFast<T1, T2, T3, T4, T5, T6>(
 366            this Expression<Action<T1, T2, T3, T4, T5, T6>> lambdaExpr, bool ifFastFailedReturnNull = false, CompilerFla
 367            (Action<T1, T2, T3, T4, T5, T6>)TryCompileBoundToFirstClosureParam(typeof(Action<T1, T2, T3, T4, T5, T6>), l
 368#if LIGHT_EXPRESSION
 369                lambdaExpr,
 370#else
 371                lambdaExpr.Parameters,
 372#endif
 373                typeof(void), flags)
 374            ?? (ifFastFailedReturnNull ? null : lambdaExpr.CompileSys());
 375
 376        #endregion
 377
 378        /// <summary>Tries to compile lambda expression to <typeparamref name="TDelegate"/></summary>
 379        public static TDelegate TryCompile<TDelegate>(this LambdaExpression lambdaExpr, CompilerFlags flags = CompilerFl
 380            where TDelegate : class =>
 381            (TDelegate)TryCompileBoundToFirstClosureParam(typeof(TDelegate) == typeof(Delegate) ? lambdaExpr.Type : type
 382#if LIGHT_EXPRESSION
 383            lambdaExpr,
 384#else
 385            lambdaExpr.Parameters,
 386#endif
 387            lambdaExpr.ReturnType, flags);
 388
 389        /// <summary>Tries to compile lambda expression to <typeparamref name="TDelegate"/>
 390        /// with the provided closure object and constant expressions (or lack there of) -
 391        /// Constant expression should be the in order of Fields in closure object!
 392        /// Note 1: Use it on your own risk - FEC won't verify the expression is compile-able with passed closure, it is
 393        /// Note 2: The expression with NESTED LAMBDA IS NOT SUPPORTED!
 394        /// Note 3: `Label` and `GoTo` are not supported in this case, because they need first round to collect out-of-o
 395        public static TDelegate TryCompileWithPreCreatedClosure<TDelegate>(this LambdaExpression lambdaExpr,
 396            params ConstantExpression[] closureConstantsExprs) where TDelegate : class =>
 397            lambdaExpr.TryCompileWithPreCreatedClosure<TDelegate>(closureConstantsExprs, CompilerFlags.Default);
 398
 399        /// <summary>Tries to compile lambda expression to <typeparamref name="TDelegate"/>
 400        /// with the provided closure object and constant expressions (or lack there of)</summary>
 401        public static TDelegate TryCompileWithPreCreatedClosure<TDelegate>(this LambdaExpression lambdaExpr,
 402            ConstantExpression[] closureConstantsExprs, CompilerFlags flags)
 403            where TDelegate : class
 404        {
 405            var closureConstants = new object[closureConstantsExprs.Length];
 406            for (var i = 0; i < closureConstants.Length; i++)
 407                closureConstants[i] = closureConstantsExprs[i].Value;
 408
 409            var closureInfo = new ClosureInfo(ClosureStatus.UserProvided | ClosureStatus.HasClosure, closureConstants);
 410            return TryCompileWithPreCreatedClosure<TDelegate>(lambdaExpr, ref closureInfo, flags);
 411        }
 412
 413        internal static TDelegate TryCompileWithPreCreatedClosure<TDelegate>(
 414            this LambdaExpression lambdaExpr, ref ClosureInfo closureInfo, CompilerFlags flags) where TDelegate : class
 415        {
 416#if LIGHT_EXPRESSION
 417            var closurePlusParamTypes = RentPooledOrNewClosureTypeToParamTypes(lambdaExpr);
 418#else
 419            var closurePlusParamTypes = RentPooledOrNewClosureTypeToParamTypes(lambdaExpr.Parameters);
 420#endif
 421            var method = new DynamicMethod(string.Empty, lambdaExpr.ReturnType, closurePlusParamTypes,
 422                typeof(ExpressionCompiler), skipVisibility: true);
 423
 424            var il = method.GetILGenerator();
 425            EmittingVisitor.EmitLoadConstantsAndNestedLambdasIntoVars(il, ref closureInfo);
 426
 427            var parent = lambdaExpr.ReturnType == typeof(void) ? ParentFlags.IgnoreResult : ParentFlags.LambdaCall;
 428            if (!EmittingVisitor.TryEmit(lambdaExpr.Body,
 429#if LIGHT_EXPRESSION
 430                lambdaExpr,
 431#else
 432                lambdaExpr.Parameters,
 433#endif
 434                il, ref closureInfo, flags, parent))
 435                return null;
 436
 437            il.Demit(OpCodes.Ret);
 438
 439            var delegateType = typeof(TDelegate) != typeof(Delegate) ? typeof(TDelegate) : lambdaExpr.Type;
 440            var dlg = (TDelegate)(object)method.CreateDelegate(delegateType, new ArrayClosure(closureInfo.Constants.Item
 441            FreePooledClosureTypeAndParamTypes(closurePlusParamTypes);
 442            return dlg;
 443        }
 444
 445        /// <summary>Tries to compile expression to "static" delegate, skipping the step of collecting the closure objec
 446        public static TDelegate TryCompileWithoutClosure<TDelegate>(this LambdaExpression lambdaExpr,
 447            CompilerFlags flags = CompilerFlags.Default) where TDelegate : class
 448        {
 449            var closureInfo = new ClosureInfo(ClosureStatus.UserProvided);
 450#if LIGHT_EXPRESSION
 451            var closurePlusParamTypes = RentPooledOrNewClosureTypeToParamTypes(lambdaExpr);
 452#else
 453            var closurePlusParamTypes = RentPooledOrNewClosureTypeToParamTypes(lambdaExpr.Parameters);
 454#endif
 455            var method = new DynamicMethod(string.Empty, lambdaExpr.ReturnType, closurePlusParamTypes, typeof(ArrayClosu
 456                skipVisibility: true);
 457
 458            var il = method.GetILGenerator();
 459            if (!EmittingVisitor.TryEmit(lambdaExpr.Body,
 460#if LIGHT_EXPRESSION
 461                lambdaExpr,
 462#else
 463                lambdaExpr.Parameters,
 464#endif
 465                il, ref closureInfo, flags, lambdaExpr.ReturnType == typeof(void) ? ParentFlags.IgnoreResult : ParentFla
 466                return null;
 467
 468            il.Demit(OpCodes.Ret);
 469
 470            var delegateType = typeof(TDelegate) != typeof(Delegate) ? typeof(TDelegate) : lambdaExpr.Type;
 471            var dlg = (TDelegate)(object)method.CreateDelegate(delegateType, EmptyArrayClosure);
 472            FreePooledClosureTypeAndParamTypes(closurePlusParamTypes);
 473            return dlg;
 474        }
 475
 476        private static Delegate CompileNoArgsNew(NewExpression newExpr, Type delegateType, Type[] closurePlusParamTypes,
 477        {
 478            var method = new DynamicMethod(string.Empty, returnType, closurePlusParamTypes, typeof(ArrayClosure), true);
 479            var il = DynamicMethodHacks.RentPooledOrNewILGenerator(method, returnType, closurePlusParamTypes, newStreamS
 480            il.Demit(OpCodes.Newobj, newExpr.Constructor);
 481            if (returnType == typeof(void))
 482                il.Demit(OpCodes.Pop);
 483            il.Demit(OpCodes.Ret);
 484
 485            var closure = (flags & CompilerFlags.EnableDelegateDebugInfo) == 0
 486                ? EmptyArrayClosure
 487                : new DebugArrayClosure(null, null, Lambda(newExpr, Tools.Empty<PE>()));
 488
 489            var dlg = method.CreateDelegate(delegateType, closure);
 490            DynamicMethodHacks.FreePooledILGenerator(method, il);
 491
 492            if (closure is DebugArrayClosure diagClosure)
 493                diagClosure.ILInstructions = dlg.Method.ReadAllInstructions();
 494
 495            return dlg;
 496        }
 497
 498#if LIGHT_EXPRESSION
 499        internal static object TryCompileBoundToFirstClosureParam(Type delegateType, Expression bodyExpr, IParameterProv
 500            Type returnType, CompilerFlags flags)
 501        {
 502            // There is no Return of the pooled parameter types here,
 503            // because in the rarest case with the unused lambda arguments we may just exhaust the pooled instance
 504            var closureAndParamTypes = RentPooledOrNewClosureTypeToParamTypes(paramExprs);
 505            if (bodyExpr is NoArgsNewClassIntrinsicExpression newExpr)
 506                return CompileNoArgsNew(newExpr, delegateType, closureAndParamTypes, returnType, flags);
 507#else
 508        internal static object TryCompileBoundToFirstClosureParam(Type delegateType, Expression bodyExpr, IReadOnlyList<
 509            Type returnType, CompilerFlags flags)
 510        {
 511            var closureAndParamTypes = RentPooledOrNewClosureTypeToParamTypes(paramExprs);
 512#endif
 513            // Try to avoid compilation altogether for Func<bool> delegates via Interpreter, see #468
 514            if (returnType == typeof(bool) & closureAndParamTypes.Length == 1
 515                && Interpreter.IsCandidateForInterpretation(bodyExpr)
 516                && Interpreter.TryInterpretBool(out var result, bodyExpr, flags))
 517                return result ? Interpreter.TrueFunc : Interpreter.FalseFunc;
 518
 519            Delegate compiledDelegate = null;
 520
 521            // The method collects the info from the all nested lambdas deep down up-front and de-duplicates the lambdas
 522            var closureInfo = new ClosureInfo(ClosureStatus.ToBeCollected);
 523            var collectResult = TryCollectInfo(ref closureInfo, bodyExpr, paramExprs, null, ref closureInfo.NestedLambda
 524            if (collectResult == Result.OK)
 525            {
 526                var constantsAndNestedLambdas = (closureInfo.Status & ClosureStatus.HasClosure) != 0
 527                    ? closureInfo.GetArrayOfConstantsAndNestedLambdas()
 528                    : null;
 529
 530                ArrayClosure closure;
 531                if ((flags & CompilerFlags.EnableDelegateDebugInfo) == 0)
 532                    closure = constantsAndNestedLambdas == null ? EmptyArrayClosure : new ArrayClosure(constantsAndNeste
 533                else
 534                {
 535                    var debugLambdaExpr = Lambda(delegateType, bodyExpr, paramExprs?.ToReadOnlyList() ?? Tools.Empty<PE>
 536                    closure = new DebugArrayClosure(null, constantsAndNestedLambdas, debugLambdaExpr);
 537                }
 538
 539                // note: @slow this is what System.Compiles does and which makes the compilation 10x slower, but the inv
 540                // var method = new DynamicMethod(string.Empty, returnType, closurePlusParamTypes, true);
 541                // this is FEC way, significantly faster compilation, but +1 branch instruction in the invocation
 542                var dynMethod = new DynamicMethod(string.Empty, returnType, closureAndParamTypes, typeof(ArrayClosure), 
 543
 544                var il = DynamicMethodHacks.RentPooledOrNewILGenerator(dynMethod, returnType, closureAndParamTypes);
 545
 546                if (closure.ConstantsAndNestedLambdas != null)
 547                    EmittingVisitor.EmitLoadConstantsAndNestedLambdasIntoVars(il, ref closureInfo);
 548
 549                var parent = returnType == typeof(void) ? ParentFlags.IgnoreResult : ParentFlags.LambdaCall;
 550                if (returnType.IsByRef)
 551                    parent |= ParentFlags.ReturnByRef;
 552
 553                if (EmittingVisitor.TryEmit(bodyExpr, paramExprs, il, ref closureInfo, flags, parent))
 554                {
 555                    il.Demit(OpCodes.Ret);
 556                    compiledDelegate = dynMethod.CreateDelegate(delegateType, closure);
 557                    if (closure is DebugArrayClosure diagClosure)
 558                        diagClosure.ILInstructions = compiledDelegate.Method.ReadAllInstructions();
 559                }
 560
 561                DynamicMethodHacks.FreePooledILGenerator(dynMethod, il);
 562            }
 563            FreePooledClosureTypeAndParamTypes(closureAndParamTypes);
 564
 565            return compiledDelegate
 566                ?? ((flags & CompilerFlags.ThrowOnNotSupportedExpression) == 0 ? null : NotSupportedCase<object>(collect
 567        }
 568
 569        private static readonly Type[] _closureAsASingleParamType = { typeof(ArrayClosure) };
 570        private static readonly Type[][] _paramTypesPoolWithElem0OfLength1 = new Type[8][]; // todo: @perf @mem could we
 571
 572#if LIGHT_EXPRESSION
 573        internal static Type[] RentPooledOrNewClosureTypeToParamTypes(IParameterProvider paramExprs)
 574        {
 575            var count = paramExprs.ParameterCount;
 576#else
 577        internal static Type[] RentPooledOrNewClosureTypeToParamTypes(IReadOnlyList<PE> paramExprs)
 578        {
 579            var count = paramExprs.Count;
 580#endif
 581            if (count == 0)
 582                return _closureAsASingleParamType;
 583
 584            var pooledOrNew = count < 8 ? Interlocked.Exchange(ref _paramTypesPoolWithElem0OfLength1[count], null) ?? ne
 585            pooledOrNew[0] = typeof(ArrayClosure);
 586            for (var i = 0; i < count; i++)
 587            {
 588                var paramExpr = paramExprs.GetParameter(i); // todo: @perf can we avoid calling virtual GetParameter() a
 589                pooledOrNew[i + 1] = !paramExpr.IsByRef ? paramExpr.Type : paramExpr.Type.MakeByRefType();
 590            }
 591
 592            return pooledOrNew;
 593        }
 594
 595        /// <summary>Renting the array of the passed parameter types</summary>
 596        [MethodImpl((MethodImplOptions)256)]
 597        public static Type[] RentPooledOrNewParamTypes(Type p0)
 598        {
 599            var pooledOrNew = Interlocked.Exchange(ref _paramTypesPoolWithElem0OfLength1[0], null) ?? new Type[1];
 600            pooledOrNew[0] = p0;
 601            return pooledOrNew;
 602        }
 603
 604        /// <summary>Renting the array of the passed parameter types</summary>
 605        [MethodImpl((MethodImplOptions)256)]
 606        public static Type[] RentPooledOrNewParamTypes(Type p0, Type p1)
 607        {
 608            var pooledOrNew = Interlocked.Exchange(ref _paramTypesPoolWithElem0OfLength1[1], null) ?? new Type[2];
 609            pooledOrNew[0] = p0;
 610            pooledOrNew[1] = p1;
 611            return pooledOrNew;
 612        }
 613
 614        /// <summary>Renting the array of the passed parameter types</summary>
 615        [MethodImpl((MethodImplOptions)256)]
 616        public static Type[] RentPooledOrNewParamTypes(Type p0, Type p1, Type p2)
 617        {
 618            var pooledOrNew = Interlocked.Exchange(ref _paramTypesPoolWithElem0OfLength1[2], null) ?? new Type[3];
 619            pooledOrNew[0] = p0;
 620            pooledOrNew[1] = p1;
 621            pooledOrNew[2] = p2;
 622            return pooledOrNew;
 623        }
 624
 625        /// <summary>Renting the array of the passed parameter types</summary>
 626        [MethodImpl((MethodImplOptions)256)]
 627        public static Type[] RentPooledOrNewParamTypes(Type p0, Type p1, Type p2, Type p3)
 628        {
 629            var pooledOrNew = Interlocked.Exchange(ref _paramTypesPoolWithElem0OfLength1[3], null) ?? new Type[4];
 630            pooledOrNew[0] = p0;
 631            pooledOrNew[1] = p1;
 632            pooledOrNew[2] = p2;
 633            pooledOrNew[3] = p3;
 634            return pooledOrNew;
 635        }
 636
 637        /// <summary>Renting the array of the passed parameter types</summary>
 638        [MethodImpl((MethodImplOptions)256)]
 639        public static Type[] RentPooledOrNewParamTypes(Type p0, Type p1, Type p2, Type p3, Type p4)
 640        {
 641            var pooledOrNew = Interlocked.Exchange(ref _paramTypesPoolWithElem0OfLength1[4], null) ?? new Type[5];
 642            pooledOrNew[0] = p0;
 643            pooledOrNew[1] = p1;
 644            pooledOrNew[2] = p2;
 645            pooledOrNew[3] = p3;
 646            pooledOrNew[4] = p4;
 647            return pooledOrNew;
 648        }
 649
 650        /// <summary>Freeing to the pool the array of types of closure + plus the passed parameter types</summary>
 651        [MethodImpl((MethodImplOptions)256)]
 652        public static void FreePooledClosureTypeAndParamTypes(Type[] closurePlusParamTypes)
 653        {
 654            var paramCountOnly = closurePlusParamTypes.Length - 1;
 655            if (paramCountOnly != 0 & paramCountOnly < 8)
 656                Interlocked.Exchange(ref _paramTypesPoolWithElem0OfLength1[paramCountOnly], closurePlusParamTypes);
 657        }
 658
 659        /// <summary>Freeing to the pool the array of the passed parameter types</summary>
 660        [MethodImpl((MethodImplOptions)256)]
 661        public static void FreePooledParamTypes(Type[] paramTypes)
 662        {
 663            var paramCount = paramTypes.Length;
 664            if (paramCount != 0 & paramCount < 8)
 665                Interlocked.Exchange(ref _paramTypesPoolWithElem0OfLength1[paramCount - 1], paramTypes);
 666        }
 667
 668
 669
 670        /// <summary>Collects the lambda info for the compilation</summary>
 671        internal sealed class NestedLambdaInfo
 672        {
 673            /// <summary>Compiled lambda</summary>
 674            public object Lambda; // todo: @perf can we use the NestedLambdaInfo itself instead of NestedLambdaWithConst
 675
 676            /// <summary>The nested lambdas and their info</summary>
 677            public SmallList<NestedLambdaInfo> NestedLambdas;
 678
 679            /// <summary>The lambda expression</summary>
 680            public LambdaExpression LambdaExpression;
 681
 682            /// <summary>Parameters not passed through lambda parameter list But used inside lambda body.
 683            /// The top expression should Not contain not passed parameters.</summary>
 684            public SmallList<ParameterExpression> NonPassedParameters;
 685
 686            /// <summary>If the N's bit is set, it means the parameter is mutated (assigned or passed by-ref),
 687            /// where N is the index of the param in `NonPassedParameters`</summary>
 688            public ulong NonPassedParamMutatedIndexBits;
 689
 690            /// <summary>Index of the compiled lambda in the parent lambda closure array</summary>
 691            public short LambdaVarIndex;
 692
 693            /// <summary>Index of the variable which store the non-passed variables array before passing it to the closu
 694            /// It used to assign the closed variables from the outside of the nested lambda</summary>
 695            public short NonPassedParamsVarIndex;
 696
 697            public NestedLambdaInfo(LambdaExpression lambdaExpression) => LambdaExpression = lambdaExpression;
 698
 699            /// <summary>Compares 2 lambda expressions for equality</summary>
 700            public bool HasTheSameLambdaExpression(LambdaExpression lambda) => // todo: @unclear parameters or is compar
 701                ReferenceEquals(LambdaExpression, lambda) ||
 702                ReferenceEquals(LambdaExpression.Body, lambda.Body)
 703#if LIGHT_EXPRESSION
 704                && LambdaExpression.ParameterCount == lambda.ParameterCount
 705#endif
 706                ;
 707
 708            public override string ToString() =>
 709                $"Lambda: {(Lambda is NestedLambdaForNonPassedParams n ? "compiled+closure" : Lambda != null ? "compiled
 710        }
 711
 712        [Flags]
 713        internal enum ClosureStatus : byte
 714        {
 715            ToBeCollected = 1,
 716            UserProvided = 1 << 1,
 717            HasClosure = 1 << 2,
 718            ShouldBeStaticMethod = 1 << 3
 719        }
 720
 721        [DebuggerDisplay("Target:{Target}, InlinedLambdaInvokeIndex:{InlinedLambdaInvokeIndex}, ReturnVariableIndexPlusO
 722        internal struct LabelInfo
 723        {
 724            public object Target;
 725            public short InlinedLambdaInvokeIndex;
 726            public short ReturnVariableIndexPlusOneAndIsDefined;
 727            public Label Label;
 728            public Label ReturnLabel;
 729        }
 730
 731        /// Track the info required to build a closure object + some context information not directly related to closure
 732        internal struct ClosureInfo
 733        {
 734            /// <summary>Tracks that the last emit was an address</summary>
 735            public bool LastEmitIsAddress;
 736
 737            // Tracks the current block nesting count in the stack of blocks in Collect and Emit phase
 738            private ushort _blockCount;
 739
 740            /// <summary>Tracks the use of the variables in the blocks stack per variable,
 741            /// (uint) contains (ushort) BlockIndex in the upper bits and (ushort) VarIndex in the lower bits.
 742            /// to determine if variable is the local variable and in what block it's defined</summary>
 743            private SmallMap4<PE, SmallList<uint, Stack4<uint>>, RefEq<PE>> _varInBlock;
 744
 745            /// The map of inlined invocations collected in TryCollect and then used in TryEmit
 746            internal SmallMap4<InvocationExpression, Expression, RefEq<InvocationExpression>> InlinedLambdaInvocation;
 747
 748            /// New or Call expressions containing the complex expression, e.g. inlined Lambda Invoke or Try with Finall
 749            internal SmallMap4<Expression, NoValue, RefEq<Expression>> ArgsContainingComplexExpression;
 750
 751            internal bool HasComplexExpression;
 752
 753            /// The stack for the lambda invocation and the labels bound to them
 754            internal SmallList<LabelInfo, Stack4<LabelInfo>> LambdaInvokeStackLabels;
 755
 756            /// Tracks of how many gotos, labels referencing the specific target, they may be the same gotos expression,
 757            /// because the gotos may be reused multiple times in the big expression
 758            internal SmallMap4<object, (ushort, ushort), RefEq<object>> TargetToGotosAndLabels;
 759
 760            /// This is required because we have the return from the nested lambda expression,
 761            /// and when inlined in the parent lambda it is no longer the return but just a jump to the label.
 762            internal short CurrentInlinedLambdaInvokeIndex;
 763
 764            public ClosureStatus Status;
 765
 766            /// Constant expressions to find an index (by reference) of constant expression from compiled expression.
 767            public SmallList<object> Constants;
 768
 769            /// Constant usage count and variable index.
 770            /// It is a separate collection from the Constants because we directly convert later into the closure array
 771            public SmallList<short, Stack2<short>> ConstantUsageThenVarIndex;
 772
 773            /// <summary>Parameters not passed through lambda parameter list But used inside lambda body.
 774            /// The top expression should Not contain not passed parameters.</summary>
 775            public SmallList<ParameterExpression> NonPassedParameters;
 776
 777            /// <summary>The nested lambdas and their info</summary>
 778            public SmallList<NestedLambdaInfo> NestedLambdas;
 779
 780            /// <summary>Populates the info</summary>
 781            public ClosureInfo(ClosureStatus status)
 782            {
 783                Status = status;
 784                Constants = new SmallList<object>();
 785                LastEmitIsAddress = false;
 786                CurrentInlinedLambdaInvokeIndex = -1;
 787            }
 788
 789            /// <summary>Populates info directly with provided closure object and constants.</summary>
 790            public ClosureInfo(ClosureStatus status, object[] constValues)
 791            {
 792                Status = status;
 793
 794                Constants = new SmallList<object>(constValues ?? Tools.Empty<object>());
 795                if (constValues != null)
 796                    ConstantUsageThenVarIndex.InitCount(constValues.Length);
 797
 798                LastEmitIsAddress = false;
 799                CurrentInlinedLambdaInvokeIndex = -1;
 800            }
 801
 802            [MethodImpl((MethodImplOptions)256)]
 803            public bool ContainsConstantsOrNestedLambdas() => Constants.Count != 0 | NestedLambdas.Count != 0;
 804
 805            public void AddConstantOrIncrementUsageCount(object value)
 806            {
 807                Status |= ClosureStatus.HasClosure;
 808                var constItems = Constants.Items;
 809                var constIndex = Constants.Count - 1;
 810                while (constIndex != -1 && !ReferenceEquals(constItems[constIndex], value))
 811                    --constIndex;
 812                if (constIndex == -1)
 813                {
 814                    Constants.Add(value);
 815                    ConstantUsageThenVarIndex.Add(1);
 816                }
 817                else
 818                {
 819                    ++ConstantUsageThenVarIndex.GetSurePresentItemRef(constIndex);
 820                }
 821            }
 822
 823            [RequiresUnreferencedCode(Trimming.Message)]
 824            public void AddLabel(LabelTarget labelTarget, short inlinedLambdaInvokeIndex = -1)
 825            {
 826                // skip null labelTargets, e.g. it may be the case for LoopExpression.Continue
 827                if (labelTarget == null)
 828                    return;
 829                GetLabelOrInvokeIndexByTarget(ref LambdaInvokeStackLabels, labelTarget, out var found);
 830                if (!found)
 831                {
 832                    ref var label = ref LambdaInvokeStackLabels.AddDefaultAndGetRef();
 833                    label.Target = labelTarget;
 834                    label.InlinedLambdaInvokeIndex = inlinedLambdaInvokeIndex;
 835                }
 836            }
 837
 838            public short AddInlinedLambdaInvoke(InvocationExpression e)
 839            {
 840                var count = LambdaInvokeStackLabels.Count;
 841                for (var i = 0; i < count; ++i)
 842                    if (LambdaInvokeStackLabels.GetSurePresentItemRef(i).Target == e)
 843                        return (short)i;
 844
 845                ref var label = ref LambdaInvokeStackLabels.AddDefaultAndGetRef();
 846                label.Target = e;
 847                return (short)count;
 848            }
 849
 850            public object[] GetArrayOfConstantsAndNestedLambdas()
 851            {
 852                var constCount = Constants.Count;
 853                var nestedLambdasCount = NestedLambdas.Count;
 854                if (constCount == 0)
 855                {
 856                    if (nestedLambdasCount == 0)
 857                        return null;
 858
 859                    var lambdaObjects = new object[nestedLambdasCount];
 860                    for (var i = 0; i < lambdaObjects.Length; i++)
 861                        lambdaObjects[i] = NestedLambdas.Items[i].Lambda;
 862                    return lambdaObjects;
 863                }
 864
 865                // if constants `count != 0`
 866                var constItems = Constants.Items;
 867                if (nestedLambdasCount == 0)
 868                    return constItems;
 869
 870                var constPlusLambdaCount = constCount + nestedLambdasCount;
 871
 872                if (constItems.Length < constPlusLambdaCount)
 873                    Array.Resize(ref constItems, constPlusLambdaCount);
 874
 875                for (var i = 0; i < nestedLambdasCount; ++i)
 876                    constItems[constCount + i] = NestedLambdas.Items[i].Lambda;
 877
 878                return constItems;
 879            }
 880
 881            /// Local variable index is not known in the collecting phase when we only need to decide if ParameterExpres
 882            [RequiresUnreferencedCode(Trimming.Message)]
 883            public void PushBlockWithVars(ParameterExpression blockVarExpr) =>
 884                PushVarInBlockMap(blockVarExpr, _blockCount++, 0);
 885
 886            [RequiresUnreferencedCode(Trimming.Message)]
 887            public void PushBlockWithVars(ParameterExpression blockVarExpr, int varIndex) =>
 888                PushVarInBlockMap(blockVarExpr, _blockCount++, (ushort)varIndex);
 889
 890            [RequiresUnreferencedCode(Trimming.Message)]
 891            public void PushBlockWithVars(IReadOnlyList<PE> blockVarExprs)
 892            {
 893                for (var i = 0; i < blockVarExprs.Count; i++)
 894                    PushVarInBlockMap(blockVarExprs[i], _blockCount, 0);
 895                ++_blockCount;
 896            }
 897
 898            [RequiresUnreferencedCode(Trimming.Message)]
 899            public void PushBlockAndConstructLocalVars(IReadOnlyList<PE> blockVarExprs, ILGenerator il)
 900            {
 901                for (var i = 0; i < blockVarExprs.Count; i++)
 902                {
 903                    var varExpr = blockVarExprs[i];
 904                    var varType = varExpr.Type;
 905                    if (varExpr.IsByRef && !varType.IsByRef)
 906                        varType = varType.MakeByRefType();
 907                    PushVarInBlockMap(varExpr, _blockCount, (ushort)il.GetNextLocalVarIndex(varType));
 908                }
 909                ++_blockCount;
 910            }
 911
 912            [MethodImpl((MethodImplOptions)256)]
 913            private void PushVarInBlockMap(ParameterExpression pe, ushort blockIndex, ushort varIndex)
 914            {
 915                ref var blocks = ref _varInBlock.Map.AddOrGetValueRef(pe, out _);
 916                if (blocks.Count == 0 || (blocks.GetLastSurePresentItem() >>> 16) != blockIndex)
 917                    blocks.Add((uint)(blockIndex << 16) | varIndex);
 918            }
 919
 920            public void PopBlock()
 921            {
 922                Debug.Assert(_blockCount > 0);
 923                var varCount = _varInBlock.Map.Count;
 924                for (var i = 0; i < varCount; ++i)
 925                {
 926                    ref var varBlocks = ref _varInBlock.Map.GetSurePresentEntryRef(i);
 927                    if (varBlocks.Value.Count == _blockCount)
 928                        varBlocks.Value.RemoveLastSurePresentItem();
 929                }
 930                --_blockCount;
 931            }
 932
 933            [MethodImpl((MethodImplOptions)256)]
 934            public bool IsLocalVar(ParameterExpression varParamExpr)
 935            {
 936                ref var blocks = ref _varInBlock.Map.TryGetValueRef(varParamExpr, out var found);
 937                return found && blocks.Count != 0;
 938            }
 939
 940            [MethodImpl((MethodImplOptions)256)]
 941            public int GetDefinedLocalVarOrDefault(ParameterExpression varParamExpr)
 942            {
 943                ref var blocks = ref _varInBlock.Map.TryGetValueRef(varParamExpr, out var found);
 944                return found && blocks.Count != 0 // rare case with the block count 0 may occur when we collected the bl
 945                    ? (int)(blocks.GetLastSurePresentItem() & ushort.MaxValue)
 946                    : -1;
 947            }
 948        }
 949
 950        internal static ref LabelInfo GetLabelOrInvokeIndexByTarget(
 951            ref this SmallList<LabelInfo, Stack4<LabelInfo>> labels, object labelTarget, out bool found)
 952        {
 953            var count = labels.Count;
 954            for (var i = 0; i < count; ++i) // todo: @perf make this loop into the SmallList method to avoid index check
 955            {
 956                ref var label = ref labels[i];
 957                if (label.Target == labelTarget)
 958                {
 959                    found = true;
 960                    return ref label;
 961                }
 962            }
 963            found = false;
 964            return ref RefTools<LabelInfo>.GetNullRef();
 965        }
 966
 967        [MethodImpl((MethodImplOptions)256)]
 968        private static Label GetOrDefineLabel(ref this LabelInfo label, ILGenerator il)
 969        {
 970            if ((label.ReturnVariableIndexPlusOneAndIsDefined & 1) == 0)
 971            {
 972                label.Label = il.DefineLabel();
 973                label.ReturnVariableIndexPlusOneAndIsDefined |= 1;
 974            }
 975            return label.Label;
 976        }
 977
 978        public static readonly ArrayClosure EmptyArrayClosure = new ArrayClosure(null);
 979
 980        public static FieldInfo ArrayClosureArrayField =
 981            typeof(ArrayClosure).GetField(nameof(ArrayClosure.ConstantsAndNestedLambdas));
 982
 983        public static FieldInfo ArrayClosureWithNonPassedParamsField =
 984            typeof(ArrayClosureWithNonPassedParams).GetField(nameof(ArrayClosureWithNonPassedParams.NonPassedParams));
 985
 986        private static ConstructorInfo[] _nonPassedParamsArrayClosureCtors = typeof(ArrayClosureWithNonPassedParams).Get
 987
 988        public static ConstructorInfo ArrayClosureWithNonPassedParamsAndConstantsCtor = _nonPassedParamsArrayClosureCtor
 989
 990        public static ConstructorInfo ArrayClosureWithNonPassedParamsCtor = _nonPassedParamsArrayClosureCtors[1];
 991
 992        private static ConstructorInfo DebugArrayClosureCtor = typeof(DebugArrayClosure).GetConstructors()[0];
 993
 994        public static Result NotSupported_RuntimeVariables { get; private set; }
 995
 996        internal class ArrayClosure
 997        {
 998            // todo: @feature split into two to reduce copying
 999            public readonly object[] ConstantsAndNestedLambdas;
 1000            public ArrayClosure(object[] constantsAndNestedLambdas) => ConstantsAndNestedLambdas = constantsAndNestedLam
 1001        }
 1002
 1003        internal static IEnumerable<IDelegateDebugInfo> EnumerateNestedLambdas(object[] constantsAndNestedLambdas)
 1004        {
 1005            if (constantsAndNestedLambdas != null && constantsAndNestedLambdas.Length != 0)
 1006                // todo: @perf how to skip until the nested lambdas fast
 1007                foreach (var item in constantsAndNestedLambdas)
 1008                {
 1009                    if (item is IDelegateDebugInfo diagInfo)
 1010                        yield return diagInfo;
 1011
 1012                    var dlg = (item is NestedLambdaForNonPassedParams nestedLambda ? nestedLambda.NestedLambda : item) a
 1013                    if (dlg != null && dlg.Target is IDelegateDebugInfo dlgDebugInfo)
 1014                        yield return dlgDebugInfo;
 1015                }
 1016        }
 1017
 1018        /// <summary>Enumerate any nested lambdas in the delegate compiled with CompilerFlags.EnableDelegateDebugInfo fl
 1019        public static IEnumerable<IDelegateDebugInfo> EnumerateNestedLambdas(
 1020            this Delegate fastCompiledDelegateWithDebugInfoFlag) =>
 1021            fastCompiledDelegateWithDebugInfoFlag.Target is ArrayClosure closure ? EnumerateNestedLambdas(closure.Consta
 1022
 1023        [RequiresUnreferencedCode(Trimming.Message)]
 1024        internal sealed class DebugArrayClosure : ArrayClosureWithNonPassedParams, IDelegateDebugInfo
 1025        {
 1026            public LambdaExpression Expression { get; internal set; }
 1027
 1028            public ILInstruction[] ILInstructions { get; internal set; }
 1029
 1030            public DebugArrayClosure(object[] nonPassedParams, object[] constantsAndNestedLambdas,
 1031                LambdaExpression expr, ILInstruction[] il = null)
 1032                : base(nonPassedParams, constantsAndNestedLambdas)
 1033            {
 1034                Expression = expr;
 1035                ILInstructions = il;
 1036            }
 1037
 1038            [RequiresUnreferencedCode(Trimming.Message)]
 1039            public IEnumerable<IDelegateDebugInfo> EnumerateNestedLambdas() =>
 1040                ExpressionCompiler.EnumerateNestedLambdas(ConstantsAndNestedLambdas);
 1041        }
 1042
 1043        // todo: @perf better to move the case with no constants to another class OR we can reuse ArrayClosure but now C
 1044        internal class ArrayClosureWithNonPassedParams : ArrayClosure
 1045        {
 1046            public readonly object[] NonPassedParams;
 1047            public ArrayClosureWithNonPassedParams(object[] nonPassedParams, object[] constantsAndNestedLambdas) : base(
 1048                NonPassedParams = nonPassedParams;
 1049            public ArrayClosureWithNonPassedParams(object[] nonPassedParams) : base(null) =>
 1050                NonPassedParams = nonPassedParams;
 1051        }
 1052
 1053        // todo: @perf this class is required until we (maybe) move to single constants list per lambda hierarchy
 1054        // Those two classes are required only if there are non-passed parameters,
 1055        // this class stores the context for creating the ArrayClosureWithNonPassedParams at the point of emitting the n
 1056        // See the #437 and #353 for the context
 1057        internal class NestedLambdaForNonPassedParams
 1058        {
 1059            public static FieldInfo NestedLambdaField =
 1060                typeof(NestedLambdaForNonPassedParams).GetField(nameof(NestedLambda));
 1061            public static FieldInfo NonPassedParamsField =
 1062                typeof(NestedLambdaForNonPassedParams).GetField(nameof(NonPassedParams));
 1063
 1064
 1065            public readonly object NestedLambda;
 1066            public object[] NonPassedParams;
 1067
 1068            public NestedLambdaForNonPassedParams(object nestedLambda) => NestedLambda = nestedLambda;
 1069        }
 1070
 1071        internal class NestedLambdaForNonPassedParamsWithConstants : NestedLambdaForNonPassedParams
 1072        {
 1073            public static FieldInfo ConstantsAndNestedLambdasField =
 1074                typeof(NestedLambdaForNonPassedParamsWithConstants).GetField(nameof(ConstantsAndNestedLambdas));
 1075
 1076            public readonly object[] ConstantsAndNestedLambdas;
 1077            public NestedLambdaForNonPassedParamsWithConstants(object nestedLambda, object[] constantsAndNestedLambdas)
 1078                : base(nestedLambda) => ConstantsAndNestedLambdas = constantsAndNestedLambdas;
 1079        }
 1080
 1081        internal sealed class NestedLambdaForNonPassedParamsWithConstantsWithDebugInfo : NestedLambdaForNonPassedParamsW
 1082        {
 1083            public LambdaExpression Expression { get; }
 1084            public ILInstruction[] ILInstructions { get; internal set; }
 1085            public NestedLambdaForNonPassedParamsWithConstantsWithDebugInfo(object nestedLambda, object[] constantsAndNe
 1086                : base(nestedLambda, constantsAndNestedLambdas) => Expression = expr;
 1087
 1088            [RequiresUnreferencedCode(Trimming.Message)]
 1089            public IEnumerable<IDelegateDebugInfo> EnumerateNestedLambdas() =>
 1090                ExpressionCompiler.EnumerateNestedLambdas(ConstantsAndNestedLambdas);
 1091        }
 1092
 1093        internal static class CurryClosureFuncs
 1094        {
 1095            public static readonly MethodInfo[] Methods = typeof(CurryClosureFuncs).GetMethods();
 1096
 1097            // todo: @mem @perf can we avoid closure creation over `f` and `c`?
 1098            public static Func<R> Curry<C, R>(Func<C, R> f, C c) =>
 1099                () => f(c);
 1100
 1101            public static Func<T1, R> Curry<C, T1, R>(Func<C, T1, R> f, C c) =>
 1102                t1 => f(c, t1);
 1103
 1104            public static Func<T1, T2, R> Curry<C, T1, T2, R>(Func<C, T1, T2, R> f, C c) =>
 1105                (t1, t2) => f(c, t1, t2);
 1106
 1107            public static Func<T1, T2, T3, R> Curry<C, T1, T2, T3, R>(Func<C, T1, T2, T3, R> f, C c) =>
 1108                (t1, t2, t3) => f(c, t1, t2, t3);
 1109
 1110            public static Func<T1, T2, T3, T4, R> Curry<C, T1, T2, T3, T4, R>(Func<C, T1, T2, T3, T4, R> f, C c) =>
 1111                (t1, t2, t3, t4) => f(c, t1, t2, t3, t4);
 1112
 1113            public static Func<T1, T2, T3, T4, T5, R> Curry<C, T1, T2, T3, T4, T5, R>(Func<C, T1, T2, T3, T4, T5, R> f,
 1114                C c) => (t1, t2, t3, t4, t5) => f(c, t1, t2, t3, t4, t5);
 1115
 1116            public static Func<T1, T2, T3, T4, T5, T6, R>
 1117                Curry<C, T1, T2, T3, T4, T5, T6, R>(Func<C, T1, T2, T3, T4, T5, T6, R> f, C c) =>
 1118                (t1, t2, t3, t4, t5, t6) => f(c, t1, t2, t3, t4, t5, t6);
 1119
 1120            public static Func<T1, T2, T3, T4, T5, T6, T7, R>
 1121                Curry<C, T1, T2, T3, T4, T5, T6, T7, R>(Func<C, T1, T2, T3, T4, T5, T6, T7, R> f, C c) =>
 1122                (t1, t2, t3, t4, t5, t6, t7) => f(c, t1, t2, t3, t4, t5, t6, t7);
 1123
 1124            public static Func<T1, T2, T3, T4, T5, T6, T7, T8, R>
 1125                Curry<C, T1, T2, T3, T4, T5, T6, T7, T8, R>(Func<C, T1, T2, T3, T4, T5, T6, T7, T8, R> f, C c) =>
 1126                (t1, t2, t3, t4, t5, t6, t7, t8) => f(c, t1, t2, t3, t4, t5, t6, t7, t8);
 1127
 1128            public static Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, R>
 1129                Curry<C, T1, T2, T3, T4, T5, T6, T7, T8, T9, R>(Func<C, T1, T2, T3, T4, T5, T6, T7, T8, T9, R> f, C c) =
 1130                (t1, t2, t3, t4, t5, t6, t7, t8, t9) => f(c, t1, t2, t3, t4, t5, t6, t7, t8, t9);
 1131
 1132            public static Func<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R>
 1133                Curry<C, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R>(Func<C, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, R>
 1134                (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) => f(c, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
 1135        }
 1136
 1137        internal static class CurryClosureActions
 1138        {
 1139            public static readonly MethodInfo[] Methods = typeof(CurryClosureActions).GetMethods();
 1140
 1141            public static Action Curry<C>(Action<C> a, C c) =>
 1142                () => a(c);
 1143
 1144            public static Action<T1> Curry<C, T1>(Action<C, T1> f, C c) =>
 1145                t1 => f(c, t1);
 1146
 1147            public static Action<T1, T2> Curry<C, T1, T2>(Action<C, T1, T2> f, C c) =>
 1148                (t1, t2) => f(c, t1, t2);
 1149
 1150            public static Action<T1, T2, T3> Curry<C, T1, T2, T3>(Action<C, T1, T2, T3> f, C c) =>
 1151                (t1, t2, t3) => f(c, t1, t2, t3);
 1152
 1153            public static Action<T1, T2, T3, T4> Curry<C, T1, T2, T3, T4>(Action<C, T1, T2, T3, T4> f, C c) =>
 1154                (t1, t2, t3, t4) => f(c, t1, t2, t3, t4);
 1155
 1156            public static Action<T1, T2, T3, T4, T5> Curry<C, T1, T2, T3, T4, T5>(Action<C, T1, T2, T3, T4, T5> f,
 1157                C c) => (t1, t2, t3, t4, t5) => f(c, t1, t2, t3, t4, t5);
 1158
 1159            public static Action<T1, T2, T3, T4, T5, T6>
 1160                Curry<C, T1, T2, T3, T4, T5, T6>(Action<C, T1, T2, T3, T4, T5, T6> f, C c) =>
 1161                (t1, t2, t3, t4, t5, t6) => f(c, t1, t2, t3, t4, t5, t6);
 1162
 1163            public static Action<T1, T2, T3, T4, T5, T6, T7>
 1164                Curry<C, T1, T2, T3, T4, T5, T6, T7>(Action<C, T1, T2, T3, T4, T5, T6, T7> f, C c) =>
 1165                (t1, t2, t3, t4, t5, t6, t7) => f(c, t1, t2, t3, t4, t5, t6, t7);
 1166
 1167            public static Action<T1, T2, T3, T4, T5, T6, T7, T8>
 1168                Curry<C, T1, T2, T3, T4, T5, T6, T7, T8>(Action<C, T1, T2, T3, T4, T5, T6, T7, T8> f, C c) =>
 1169                (t1, t2, t3, t4, t5, t6, t7, t8) => f(c, t1, t2, t3, t4, t5, t6, t7, t8);
 1170
 1171            public static Action<T1, T2, T3, T4, T5, T6, T7, T8, T9>
 1172                Curry<C, T1, T2, T3, T4, T5, T6, T7, T8, T9>(Action<C, T1, T2, T3, T4, T5, T6, T7, T8, T9> f, C c) =>
 1173                (t1, t2, t3, t4, t5, t6, t7, t8, t9) => f(c, t1, t2, t3, t4, t5, t6, t7, t8, t9);
 1174
 1175            public static Action<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>
 1176                Curry<C, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(Action<C, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> f, 
 1177                (t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) => f(c, t1, t2, t3, t4, t5, t6, t7, t8, t9, t10);
 1178        }
 1179
 1180        #region Collect Bound Constants
 1181
 1182        /// Helps to identify constants as the one to be put into the Closure
 1183        public static bool IsClosureBoundConstant(object value, Type type) =>
 1184            value is Delegate || type.IsArray ||
 1185            !type.IsPrimitive && !type.IsEnum && value is string == false && value is Type == false && value is decimal 
 1186
 1187        internal enum Result
 1188        {
 1189            OK = 0,
 1190            ExpressionIsNull = 1,
 1191            ParameterIsNotVariableNorInPassedParameters = 2,
 1192            NestedLambdaCompileError = 102,
 1193            NotSupported_UnknownExpression = 1000,
 1194            /// <summary>Multi-dimensional array initializer is not supported</summary>
 1195            NotSupported_NewArrayInit_MultidimensionalArray = 1001,
 1196            /// <summary>Quote is not supported</summary>
 1197            NotSupported_Quote = 1002,
 1198            /// <summary>Dynamic is not supported</summary>
 1199            NotSupported_Dynamic = 1003,
 1200            /// <summary>RuntimeVariables is not supported</summary>
 1201            NotSupported_RuntimeVariables = 1004,
 1202            /// <summary>MemberInit MemberBinding is not supported</summary>
 1203            NotSupported_MemberInit_MemberBinding = 1005,
 1204            /// <summary>MemberInit ListBinding is not supported</summary>
 1205            NotSupported_MemberInit_ListBinding = 1006,
 1206            /// <summary>Goto of the Return kind from the TryCatch is not supported</summary>
 1207            NotSupported_Try_GotoReturnToTheFollowupLabel = 1007,
 1208            /// <summary>Not supported assignment target</summary>
 1209            NotSupported_Assign_Target = 1008,
 1210            /// <summary>TypeEqual is not supported </summary>
 1211            NotSupported_TypeEqual = 1009,
 1212            /// <summary>`when` in catch is not supported yet</summary>
 1213            NotSupported_ExceptionCatchFilter = 1010
 1214        }
 1215
 1216        /// <summary>Return value is ignored</summary>
 1217        [MethodImpl(MethodImplOptions.NoInlining)]
 1218        internal static T NotSupportedCase<T>(Result reason)
 1219        {
 1220            if (reason == Result.OK)
 1221            {
 1222                Debug.WriteLine($"Not support case found in TryEmit phase because the TryCollect phase is {reason}");
 1223                Debugger.Break();
 1224            }
 1225            Debug.WriteLine($"Not supported case is found with the reason: {reason}");
 1226            throw new NotSupportedExpressionException(reason);
 1227        }
 1228
 1229        /// <summary>Wraps the call to `TryCollectInfo` for the compatibility and provide the root place to check the re
 1230        /// Important: The method collects the info from the nested lambdas up-front and de-duplicates the lambdas as we
 1231        [MethodImpl((MethodImplOptions)256)]
 1232        public static bool TryCollectBoundConstants(ref ClosureInfo closure, Expression expr,
 1233#if LIGHT_EXPRESSION
 1234            IParameterProvider paramExprs, // `paramExprs` are required for nested lambda compilation
 1235#else
 1236            IReadOnlyList<PE> paramExprs,
 1237#endif
 1238            NestedLambdaInfo nestedLambda, ref SmallList<NestedLambdaInfo> rootNestedLambdas, CompilerFlags flags)
 1239        {
 1240            var r = TryCollectInfo(ref closure, expr, paramExprs, nestedLambda, ref rootNestedLambdas, flags);
 1241            return r == Result.OK || (flags & CompilerFlags.ThrowOnNotSupportedExpression) != 0 && NotSupportedCase<bool
 1242        }
 1243
 1244        /// <summary>Collects the information about closure constants, nested lambdas, non-passed parameters, goto label
 1245        /// Returns `OK` result if everything is fine and other result for error.</summary>
 1246        public static Result TryCollectInfo(ref ClosureInfo closure, Expression expr,
 1247#if LIGHT_EXPRESSION
 1248            IParameterProvider paramExprs,
 1249#else
 1250            IReadOnlyList<PE> paramExprs,
 1251#endif
 1252            NestedLambdaInfo nestedLambda, ref SmallList<NestedLambdaInfo> rootNestedLambdas, CompilerFlags flags)
 1253        {
 1254            var r = Result.OK;
 1255            while (true)
 1256            {
 1257                if (expr == null)
 1258                    return Result.ExpressionIsNull;
 1259#if LIGHT_EXPRESSION
 1260                if (expr.IsIntrinsic)
 1261                    return expr.TryCollectInfo(flags, ref closure, paramExprs, nestedLambda, ref rootNestedLambdas);
 1262#endif
 1263                switch (expr.NodeType)
 1264                {
 1265                    case ExpressionType.Constant:
 1266#if LIGHT_EXPRESSION
 1267                        if (expr == NullConstant | expr == FalseConstant | expr == TrueConstant || expr is IntConstantEx
 1268                            return r;
 1269#endif
 1270                        var constantExpr = (ConstantExpression)expr;
 1271                        var value = constantExpr.Value;
 1272                        if (value != null && IsClosureBoundConstant(value, value.GetType()))
 1273                            closure.AddConstantOrIncrementUsageCount(value);
 1274                        return Result.OK;
 1275
 1276                    case ExpressionType.Parameter:
 1277                        {
 1278#if LIGHT_EXPRESSION
 1279                            var paramCount = paramExprs.ParameterCount;
 1280#else
 1281                            var paramCount = paramExprs.Count;
 1282#endif
 1283                            // if parameter is used BUT is not in passed parameters and not in local variables,
 1284                            // it means parameter is provided by outer lambda and should be put in closure for current l
 1285                            var p = paramCount - 1;
 1286                            var parExpr = (PE)expr;
 1287                            while (p != -1 && !ReferenceEquals(paramExprs.GetParameter(p), parExpr)) --p;
 1288                            if (p == -1 && !closure.IsLocalVar(parExpr))
 1289                            {
 1290                                if (nestedLambda == null) // means that we are in the root lambda
 1291                                    return Result.ParameterIsNotVariableNorInPassedParameters;
 1292                                closure.Status |= ClosureStatus.HasClosure;
 1293                                _ = nestedLambda.NonPassedParameters.GetIndexOrAdd(parExpr, default(RefEq<ParameterExpre
 1294                            }
 1295                            return Result.OK;
 1296                        }
 1297                    case ExpressionType.Call:
 1298                        {
 1299                            var callExpr = (MethodCallExpression)expr;
 1300                            var callObjectExpr = callExpr.Object;
 1301
 1302#if SUPPORTS_ARGUMENT_PROVIDER
 1303                            var callArgs = (IArgumentProvider)callExpr;
 1304#else
 1305                            var callArgs = callExpr.Arguments;
 1306#endif
 1307                            var argCount = callArgs.GetCount();
 1308                            if (argCount == 0)
 1309                            {
 1310                                if (callObjectExpr != null)
 1311                                {
 1312                                    expr = callObjectExpr;
 1313                                    continue;
 1314                                }
 1315                                return Result.OK;
 1316                            }
 1317
 1318                            if (callObjectExpr != null &&
 1319                                (r = TryCollectInfo(ref closure, callObjectExpr, paramExprs, nestedLambda, ref rootNeste
 1320                                return r;
 1321
 1322                            var hasComplexExpression = false;
 1323                            for (var i = 0; i < argCount; i++)
 1324                            {
 1325                                closure.HasComplexExpression = false; // reset the flag because we want to know the real
 1326                                if ((r = TryCollectInfo(ref closure, callArgs.GetArgument(i), paramExprs, nestedLambda, 
 1327                                    return r;
 1328                                // if any argument is complex, then thw whole call should be complex,
 1329                                // because we cannot just store and restore a single argument, it should be done for all
 1330                                hasComplexExpression |= closure.HasComplexExpression;
 1331                            }
 1332
 1333                            // propagate the value up the stack
 1334                            if (hasComplexExpression)
 1335                            {
 1336                                closure.HasComplexExpression = true;
 1337                                closure.ArgsContainingComplexExpression.Map.AddOrGetValueRef(callExpr, out _);
 1338                            }
 1339                            return r;
 1340                        }
 1341
 1342                    case ExpressionType.MemberAccess:
 1343                        var memberExpr = ((MemberExpression)expr).Expression;
 1344                        if (memberExpr == null)
 1345                            return r;
 1346                        expr = memberExpr;
 1347                        continue;
 1348
 1349                    case ExpressionType.New:
 1350                        {
 1351                            var newExpr = (NewExpression)expr;
 1352#if SUPPORTS_ARGUMENT_PROVIDER
 1353                            var ctorArgs = (IArgumentProvider)newExpr;
 1354#else
 1355                            var ctorArgs = newExpr.Arguments;
 1356#endif
 1357                            var argCount = ctorArgs.GetCount();
 1358                            if (argCount == 0)
 1359                                return r;
 1360
 1361                            var hasComplexExpression = false;
 1362                            for (var i = 0; i < argCount; i++)
 1363                            {
 1364                                closure.HasComplexExpression = false;
 1365                                if ((r = TryCollectInfo(ref closure, ctorArgs.GetArgument(i), paramExprs, nestedLambda, 
 1366                                    return r;
 1367                                hasComplexExpression |= closure.HasComplexExpression;
 1368                            }
 1369
 1370                            // pop the value up the stack
 1371                            if (hasComplexExpression)
 1372                            {
 1373                                closure.HasComplexExpression = true;
 1374                                closure.ArgsContainingComplexExpression.Map.AddOrGetEntryRef(newExpr, out _);
 1375                            }
 1376
 1377                            return r;
 1378                        }
 1379                    case ExpressionType.NewArrayBounds:
 1380                    case ExpressionType.NewArrayInit:
 1381                        // todo: @feature multi-dimensional array initializers are not supported yet, they also are not 
 1382                        if (expr.NodeType == ExpressionType.NewArrayInit && expr.Type.GetArrayRank() > 1)
 1383                            return Result.NotSupported_NewArrayInit_MultidimensionalArray;
 1384#if LIGHT_EXPRESSION
 1385                        var arrElems = (IArgumentProvider)expr;
 1386                        var elemCount = arrElems.ArgumentCount;
 1387#else
 1388                        var arrElems = ((NewArrayExpression)expr).Expressions;
 1389                        var elemCount = arrElems.Count;
 1390#endif
 1391                        if (elemCount == 0)
 1392                            return r;
 1393                        for (var i = 0; i < elemCount - 1; i++)
 1394                            if ((r = TryCollectInfo(ref closure, arrElems.GetArgument(i), paramExprs, nestedLambda, ref 
 1395                                return r;
 1396                        expr = arrElems.GetArgument(elemCount - 1);
 1397                        continue;
 1398
 1399                    case ExpressionType.MemberInit:
 1400                        return TryCollectMemberInitExprConstants(
 1401                            ref closure, (MemberInitExpression)expr, paramExprs, nestedLambda, ref rootNestedLambdas, fl
 1402
 1403                    case ExpressionType.ListInit:
 1404                        return TryCollectListInitExprConstants(
 1405                            ref closure, (ListInitExpression)expr, paramExprs, nestedLambda, ref rootNestedLambdas, flag
 1406
 1407                    case ExpressionType.Lambda:
 1408                        // Here we look if the lambda is already stored in the nested lambdas tree (Collected+Compiled),
 1409                        // or if not found it Collects+Compiles the nested lambda here and adds to the nested lambda tre
 1410                        var nestedLambdaExpr = (LambdaExpression)expr;
 1411
 1412#if LIGHT_EXPRESSION // todo: @simplify can we do better?
 1413                        var nestedParamExprs = (IParameterProvider)nestedLambdaExpr;
 1414#else
 1415                        var nestedParamExprs = nestedLambdaExpr.Parameters;
 1416#endif
 1417                        closure.Status |= ClosureStatus.HasClosure;
 1418
 1419                        // Look for the already collected lambdas starting from the root
 1420                        if (rootNestedLambdas.Count != 0 &&
 1421                            FindAlreadyCompiledNestedLambdaInfoInLambdas(ref rootNestedLambdas, nestedLambdaExpr, out va
 1422                        {
 1423                            if (nestedLambda != null)
 1424                                nestedLambda.NestedLambdas.Add(compiledNestedLambda);
 1425                            else
 1426                                rootNestedLambdas.Add(compiledNestedLambda);
 1427
 1428                            if (compiledNestedLambda.NonPassedParameters.Count != 0 &&
 1429                                !PropagateNonPassedParamsToOuterLambda(ref closure,
 1430                                    nestedLambda, paramExprs, nestedParamExprs, ref compiledNestedLambda.NonPassedParame
 1431                                return Result.ParameterIsNotVariableNorInPassedParameters;
 1432
 1433                            return r;
 1434                        }
 1435
 1436                        var nestedClosure = new ClosureInfo(ClosureStatus.ToBeCollected);
 1437                        var newNestedLambda = new NestedLambdaInfo(nestedLambdaExpr);
 1438
 1439                        if (nestedLambda != null)
 1440                            nestedLambda.NestedLambdas.Add(newNestedLambda);
 1441                        else
 1442                            rootNestedLambdas.Add(newNestedLambda);
 1443
 1444                        if ((r = TryCollectInfo(ref nestedClosure, nestedLambdaExpr.Body, nestedParamExprs, newNestedLam
 1445                            return r;
 1446
 1447                        if (newNestedLambda.NonPassedParameters.Count != 0 &&
 1448                            !PropagateNonPassedParamsToOuterLambda(ref closure,
 1449                                nestedLambda, paramExprs, nestedParamExprs, ref newNestedLambda.NonPassedParameters))
 1450                            return Result.ParameterIsNotVariableNorInPassedParameters;
 1451
 1452                        if (!TryCompileNestedLambda(ref nestedClosure, newNestedLambda, flags))
 1453                            return Result.NestedLambdaCompileError;
 1454
 1455                        return r;
 1456
 1457                    case ExpressionType.Invoke:
 1458                        {
 1459                            var invokeExpr = (InvocationExpression)expr;
 1460#if SUPPORTS_ARGUMENT_PROVIDER
 1461                            var invokeArgs = (IArgumentProvider)invokeExpr;
 1462#else
 1463                            var invokeArgs = invokeExpr.Arguments;
 1464#endif
 1465                            var invokeArgCount = invokeArgs.GetCount();
 1466                            var invokedExpr = invokeExpr.Expression;
 1467                            if ((flags & CompilerFlags.NoInvocationLambdaInlining) == 0 && invokedExpr is LambdaExpressi
 1468                            {
 1469                                var oldIndex = closure.CurrentInlinedLambdaInvokeIndex;
 1470                                closure.CurrentInlinedLambdaInvokeIndex = closure.AddInlinedLambdaInvoke(invokeExpr);
 1471                                closure.HasComplexExpression = false; // switch off because we have entered the inlined 
 1472
 1473                                ref var inlinedExpr = ref closure.InlinedLambdaInvocation.Map.AddOrGetValueRef(invokeExp
 1474                                if (!found)
 1475                                    inlinedExpr = CreateInlinedLambdaInvocationExpression(invokeArgs, invokeArgCount, la
 1476
 1477                                if ((r = TryCollectInfo(ref closure, inlinedExpr, paramExprs, nestedLambda, ref rootNest
 1478                                    return r;
 1479
 1480                                closure.HasComplexExpression = true;
 1481                                closure.CurrentInlinedLambdaInvokeIndex = oldIndex;
 1482                                return r;
 1483                            }
 1484
 1485                            // No inlining, collect the normal way
 1486                            if (invokeArgCount == 0)
 1487                            {
 1488                                expr = invokedExpr;
 1489                                continue;
 1490                            }
 1491
 1492                            if ((r = TryCollectInfo(ref closure, invokedExpr, paramExprs, nestedLambda, ref rootNestedLa
 1493                                return r;
 1494
 1495                            var lastArgIndex = invokeArgCount - 1;
 1496                            for (var i = 0; i < lastArgIndex; i++)
 1497                                if ((r = TryCollectInfo(ref closure, invokeArgs.GetArgument(i), paramExprs, nestedLambda
 1498                                    return r;
 1499                            expr = invokeArgs.GetArgument(lastArgIndex);
 1500                            continue;
 1501                        }
 1502                    case ExpressionType.Conditional:
 1503                        var condExpr = (ConditionalExpression)expr;
 1504                        if ((r = TryCollectInfo(ref closure, condExpr.Test, paramExprs, nestedLambda, ref rootNestedLamb
 1505                            (r = TryCollectInfo(ref closure, condExpr.IfFalse, paramExprs, nestedLambda, ref rootNestedL
 1506                            return r;
 1507                        expr = condExpr.IfTrue;
 1508                        continue;
 1509
 1510                    case ExpressionType.Block:
 1511                        var blockExpr = (BlockExpression)expr;
 1512                        var blockExprs = blockExpr.Expressions;
 1513                        var blockExprCount = blockExprs.Count;
 1514                        if (blockExprCount == 0)
 1515                            return r; // yeah, this is the real case - the block may not contain any expressions
 1516
 1517                        var varExprs = blockExpr.Variables;
 1518                        var varExprCount = varExprs?.Count ?? 0; // todo: @perf optimize for an empty and a single varia
 1519
 1520                        if (varExprCount == 1 & blockExprCount == 2 &&
 1521                            blockExprs[0] is BinaryExpression st0 && st0.NodeType == ExpressionType.Assign &&
 1522                            blockExprs[1] is BinaryExpression st1 && st1.NodeType == ExpressionType.Assign &&
 1523                            st0.Left == blockExprs[0] && st1.Right == blockExprs[0])
 1524                        {
 1525                            if ((r = TryCollectInfo(ref closure, st0.Right, paramExprs, nestedLambda, ref rootNestedLamb
 1526                                return r;
 1527                            expr = st1.Left;
 1528                            continue;
 1529                        }
 1530
 1531                        if (varExprCount == 1)
 1532                            closure.PushBlockWithVars(varExprs[0]);
 1533                        else if (varExprCount != 0)
 1534                            closure.PushBlockWithVars(varExprs);
 1535
 1536                        for (var i = 0; i < blockExprCount - 1; i++)
 1537                            if ((r = TryCollectInfo(ref closure, blockExprs[i], paramExprs, nestedLambda, ref rootNested
 1538                                return r;
 1539
 1540                        expr = blockExprs[blockExprCount - 1];
 1541                        if (varExprCount == 0)
 1542                            continue; // in case of no variables we can collect the last expr without recursion
 1543
 1544                        if ((r = TryCollectInfo(ref closure, expr, paramExprs, nestedLambda, ref rootNestedLambdas, flag
 1545                            return r;
 1546                        closure.PopBlock();
 1547                        return r;
 1548
 1549                    case ExpressionType.Loop:
 1550                        var loopExpr = (LoopExpression)expr;
 1551                        closure.AddLabel(loopExpr.BreakLabel);
 1552                        closure.AddLabel(loopExpr.ContinueLabel);
 1553                        expr = loopExpr.Body;
 1554                        continue;
 1555
 1556                    case ExpressionType.Index:
 1557                        var indexExpr = (IndexExpression)expr;
 1558#if SUPPORTS_ARGUMENT_PROVIDER
 1559                        var indexArgs = (IArgumentProvider)indexExpr;
 1560#else
 1561                        var indexArgs = indexExpr.Arguments;
 1562#endif
 1563                        var indexArgCount = indexArgs.GetCount();
 1564                        for (var i = 0; i < indexArgCount; i++)
 1565                            if ((r = TryCollectInfo(ref closure, indexArgs.GetArgument(i), paramExprs, nestedLambda, ref
 1566                                return r;
 1567                        if (indexExpr.Object == null)
 1568                            return r;
 1569                        expr = indexExpr.Object;
 1570                        continue;
 1571
 1572                    case ExpressionType.Try:
 1573                        {
 1574                            closure.HasComplexExpression = false;
 1575                            r = TryCollectTryExprInfo(ref closure, (TryExpression)expr, paramExprs, nestedLambda, ref ro
 1576                            closure.HasComplexExpression = true;
 1577                            return r;
 1578                        }
 1579                    case ExpressionType.Label:
 1580                        var labelExpr = (LabelExpression)expr;
 1581                        closure.AddLabel(labelExpr.Target, closure.CurrentInlinedLambdaInvokeIndex);
 1582                        if (labelExpr.Target != null)
 1583                            closure.TargetToGotosAndLabels.Map.AddOrGetValueRef(labelExpr.Target, out _).Item2++;
 1584                        if (labelExpr.DefaultValue == null)
 1585                            return r;
 1586                        expr = labelExpr.DefaultValue;
 1587                        continue;
 1588
 1589                    case ExpressionType.Goto:
 1590                        var gotoExpr = (GotoExpression)expr;
 1591                        if (gotoExpr.Target != null)
 1592                            closure.TargetToGotosAndLabels.Map.AddOrGetValueRef(gotoExpr.Target, out _).Item1++;
 1593                        if (gotoExpr.Value == null)
 1594                            return r;
 1595                        expr = gotoExpr.Value;
 1596                        continue;
 1597
 1598                    case ExpressionType.Switch:
 1599                        var switchExpr = ((SwitchExpression)expr);
 1600                        if ((r = TryCollectInfo(ref closure, switchExpr.SwitchValue, paramExprs, nestedLambda, ref rootN
 1601                            switchExpr.DefaultBody != null && // todo: @check is the order of collection affects the res
 1602                            (r = TryCollectInfo(ref closure, switchExpr.DefaultBody, paramExprs, nestedLambda, ref rootN
 1603                            return r;
 1604
 1605                        var switchCases = switchExpr.Cases;
 1606                        if (switchCases.Count != 0)
 1607                        {
 1608                            for (var i = 0; i < switchCases.Count - 1; i++)
 1609                                if ((r = TryCollectInfo(ref closure, switchCases[i].Body, paramExprs, nestedLambda, ref 
 1610                                    return r;
 1611                            expr = switchCases[switchCases.Count - 1].Body;
 1612                            continue;
 1613                        }
 1614                        return r;
 1615
 1616                    case ExpressionType.Extension:
 1617                        expr = expr.Reduce();
 1618                        continue;
 1619
 1620                    case ExpressionType.Default:
 1621                        return r;
 1622
 1623                    case ExpressionType.TypeIs:
 1624                    case ExpressionType.TypeEqual:
 1625                        expr = ((TypeBinaryExpression)expr).Expression;
 1626                        continue;
 1627
 1628                    case ExpressionType.Quote:            // todo: @feature - is not supported yet
 1629                        return Result.NotSupported_Quote;
 1630                    case ExpressionType.Dynamic:          // todo: @feature - is not supported yet
 1631                        return Result.NotSupported_Dynamic;
 1632                    case ExpressionType.RuntimeVariables: // todo: @feature - is not supported yet
 1633                        return NotSupported_RuntimeVariables;
 1634
 1635                    case ExpressionType.DebugInfo: // todo: @feature - is not supported yet
 1636                        return r;                  // todo: @unclear - just ignoring the info for now
 1637
 1638                    default:
 1639                        if (expr is UnaryExpression unaryExpr)
 1640                        {
 1641                            if (unaryExpr.Operand is null)
 1642                                return r;
 1643                            expr = unaryExpr.Operand;
 1644                            continue;
 1645                        }
 1646
 1647                        if (expr is BinaryExpression binaryExpr)
 1648                        {
 1649                            if ((r = TryCollectInfo(ref closure, binaryExpr.Left, paramExprs, nestedLambda, ref rootNest
 1650                                return r;
 1651                            expr = binaryExpr.Right;
 1652                            continue;
 1653                        }
 1654
 1655                        return Result.NotSupported_UnknownExpression;
 1656                }
 1657            }
 1658        }
 1659
 1660        private static Expression CreateInlinedLambdaInvocationExpression(
 1661#if SUPPORTS_ARGUMENT_PROVIDER
 1662            IArgumentProvider invokeArgs,
 1663#else
 1664            IReadOnlyList<Expression> invokeArgs,
 1665#endif
 1666            int invokeArgCount, LambdaExpression lambdaExpr)
 1667        {
 1668            // Check the actual lambda return type in case it differs from the Body type,
 1669            // e.g. often case for the Action lambdas where the Body type is ignored in favor of `void`.
 1670            var lambdaReturnType = lambdaExpr.ReturnType;
 1671            var lambdaBodyExpr = lambdaExpr.Body;
 1672            if (invokeArgCount == 0)
 1673                return lambdaReturnType == lambdaBodyExpr.Type ? lambdaBodyExpr :
 1674                lambdaReturnType == typeof(void) ? Block(typeof(void), lambdaBodyExpr) :
 1675                Convert(lambdaBodyExpr, lambdaReturnType);
 1676
 1677            // To inline the lambda we will wrap its body into a block, parameters into the block variables,
 1678            // and the invocation arguments into the variable assignments, see #278.
 1679#if LIGHT_EXPRESSION
 1680            var lambdaPars = (IParameterProvider)lambdaExpr;
 1681#else
 1682            var lambdaPars = lambdaExpr.Parameters;
 1683#endif
 1684            SmallList<Expression, Stack2<Expression>> inlinedBlockExprs = default;
 1685            SmallList<ParameterExpression, Stack2<ParameterExpression>> savedVars = default;
 1686            SmallList<Expression, Stack2<Expression>> savedVarsBlockExprs = default;
 1687
 1688            for (var i = 0; i < invokeArgCount; i++)
 1689            {
 1690                var lambdaPar = lambdaPars.GetParameter(i);
 1691                var invokeArg = invokeArgs.GetArgument(i);
 1692
 1693                // The case of reusing the parameters or variables in the different lambdas,
 1694                // see the test `NestedLambdaTests.Hmm_I_can_use_the_same_parameter_for_outer_and_nested_lambda`
 1695                // and the `Issue401_What_happens_if_inlined_invocation_of_lambda_overrides_the_same_parameter`.
 1696                if (lambdaPar == invokeArg)
 1697                {
 1698                    var savedPar = Parameter(lambdaPar.Type, lambdaPar.Name + "_" + lambdaPar.GetHashCode().ToString());
 1699                    savedVars.Add(savedPar);
 1700                    savedVarsBlockExprs.Add(Assign(savedPar, invokeArg));
 1701                    inlinedBlockExprs.Add(Assign(lambdaPar, savedPar));
 1702                    continue;
 1703                }
 1704
 1705                inlinedBlockExprs.Add(Assign(lambdaPar, invokeArg));
 1706            }
 1707
 1708            inlinedBlockExprs.Add(lambdaBodyExpr);
 1709
 1710#if LIGHT_EXPRESSION
 1711            var inlinedBlock = lambdaReturnType == lambdaBodyExpr.Type
 1712                ? Block(lambdaPars.ToReadOnlyList(), in inlinedBlockExprs)
 1713                : Block(lambdaReturnType, lambdaPars.ToReadOnlyList(), in inlinedBlockExprs);
 1714            if (savedVars.Count != 0)
 1715            {
 1716                savedVarsBlockExprs.Add(inlinedBlock);
 1717                inlinedBlock = Block(savedVars.ToArray(), in savedVarsBlockExprs);
 1718            }
 1719#else
 1720            var inlinedBlock = lambdaReturnType == lambdaBodyExpr.Type
 1721                ? Block(lambdaPars, inlinedBlockExprs.ToArray())
 1722                : Block(lambdaReturnType, lambdaPars, inlinedBlockExprs.ToArray());
 1723            if (savedVars.Count != 0)
 1724            {
 1725                savedVarsBlockExprs.Add(inlinedBlock);
 1726                inlinedBlock = Block(savedVars.ToArray(), savedVarsBlockExprs.ToArray());
 1727            }
 1728#endif
 1729            return inlinedBlock;
 1730        }
 1731
 1732#if LIGHT_EXPRESSION
 1733        private static bool PropagateNonPassedParamsToOuterLambda(ref ClosureInfo closure, NestedLambdaInfo lambda,
 1734            IParameterProvider paramExprs, IParameterProvider nestedLambdaParamExprs, ref SmallList<ParameterExpression>
 1735        {
 1736            var paramExprCount = paramExprs.ParameterCount;
 1737            var nestedLambdaParamExprCount = nestedLambdaParamExprs.ParameterCount;
 1738#else
 1739        private static bool PropagateNonPassedParamsToOuterLambda(ref ClosureInfo closure, NestedLambdaInfo lambda,
 1740            IReadOnlyList<PE> paramExprs, IReadOnlyList<PE> nestedLambdaParamExprs, ref SmallList<ParameterExpression> n
 1741        {
 1742            var paramExprCount = paramExprs.Count;
 1743            var nestedLambdaParamExprCount = nestedLambdaParamExprs.Count;
 1744#endif
 1745            // If nested non passed parameter is not matched with any outer passed parameter,
 1746            // then we ensure it goes to the outer non passed parameter.
 1747            // But having the non-passed parameter in the root expression (nestedLambda == null) is invalid, and results
 1748            for (var i = 0; i < nestedNonPassedParams.Count; i++)
 1749            {
 1750                var nestedNonPassedParam = nestedNonPassedParams.GetSurePresentItemRef(i);
 1751
 1752                var isInNestedLambda = false;
 1753                if (nestedLambdaParamExprCount != 0)
 1754                    for (var p = 0; !isInNestedLambda && p < nestedLambdaParamExprCount; ++p)
 1755                        isInNestedLambda = ReferenceEquals(nestedLambdaParamExprs.GetParameter(p), nestedNonPassedParam)
 1756
 1757                var isInLambda = false;
 1758                if (paramExprCount != 0)
 1759                    for (var p = 0; !isInLambda && p < paramExprCount; ++p)
 1760                        isInLambda = ReferenceEquals(paramExprs.GetParameter(p), nestedNonPassedParam);
 1761
 1762                if (!isInNestedLambda & !isInLambda)
 1763                {
 1764                    if (closure.IsLocalVar(nestedNonPassedParam))
 1765                        continue;
 1766                    if (lambda == null) // means that we at the root level lambda, and non-passed parameter cannot be pr
 1767                        return false;
 1768                    _ = lambda.NonPassedParameters.GetIndexOrAdd(nestedNonPassedParam, default(RefEq<ParameterExpression
 1769                }
 1770            }
 1771
 1772            return true;
 1773        }
 1774
 1775        private static bool FindAlreadyCompiledNestedLambdaInfoInLambdas(
 1776            ref SmallList<NestedLambdaInfo> nestedLambdas, LambdaExpression lambdaExpr, out NestedLambdaInfo found)
 1777        {
 1778            var nestedLambdasCount = nestedLambdas.Count;
 1779            for (var i = 0; i < nestedLambdasCount; ++i)
 1780            {
 1781                var nestedLambda = nestedLambdas.Items[i];
 1782                if (nestedLambda.HasTheSameLambdaExpression(lambdaExpr))
 1783                {
 1784                    found = nestedLambda;
 1785                    return true;
 1786                }
 1787
 1788                if (nestedLambda.NestedLambdas.Count != 0)
 1789                    return FindAlreadyCompiledNestedLambdaInfoInLambdas(ref nestedLambda.NestedLambdas, lambdaExpr, out 
 1790            }
 1791
 1792            found = null;
 1793            return false;
 1794        }
 1795
 1796        private static bool TryCompileNestedLambda(ref ClosureInfo nestedClosureInfo, NestedLambdaInfo nestedLambdaInfo,
 1797        {
 1798            // 1. Try to compile nested lambda in place
 1799            // 2. Check that parameters used in compiled lambda are passed or closed by outer lambda
 1800            // 3. Add the compiled lambda to closure of outer lambda for later invocation
 1801            var nestedLambdaExpr = nestedLambdaInfo.LambdaExpression;
 1802            var nestedReturnType = nestedLambdaExpr.ReturnType;
 1803            var nestedLambdaBody = nestedLambdaExpr.Body;
 1804#if LIGHT_EXPRESSION
 1805            var nestedLambdaParamExprs = (IParameterProvider)nestedLambdaExpr;
 1806
 1807            if (nestedLambdaBody is NoArgsNewClassIntrinsicExpression newExpr)
 1808            {
 1809                var paramTypes = RentPooledOrNewClosureTypeToParamTypes(nestedLambdaParamExprs);
 1810                nestedLambdaInfo.Lambda = CompileNoArgsNew(newExpr, nestedLambdaExpr.Type, paramTypes, nestedReturnType,
 1811                FreePooledClosureTypeAndParamTypes(paramTypes);
 1812                return true;
 1813            }
 1814#else
 1815            var nestedLambdaParamExprs = nestedLambdaExpr.Parameters;
 1816#endif
 1817            // copy the nested lambdas and non-passed parameters to closure info to read them in TryEmit
 1818            nestedClosureInfo.NestedLambdas = nestedLambdaInfo.NestedLambdas;
 1819            nestedClosureInfo.NonPassedParameters = nestedLambdaInfo.NonPassedParameters;
 1820
 1821            var constantsAndNestedLambdas = (nestedClosureInfo.Status & ClosureStatus.HasClosure) != 0
 1822                ? nestedClosureInfo.GetArrayOfConstantsAndNestedLambdas()
 1823                : null;
 1824
 1825            ArrayClosure nestedLambdaClosure = null;
 1826            var hasDebugInfo = (flags & CompilerFlags.EnableDelegateDebugInfo) != 0;
 1827            var hasNonPassedParameters = nestedLambdaInfo.NonPassedParameters.Count != 0;
 1828            if (!hasNonPassedParameters)
 1829                nestedLambdaClosure = !hasDebugInfo
 1830                    ? (constantsAndNestedLambdas == null ? EmptyArrayClosure : new ArrayClosure(constantsAndNestedLambda
 1831                    : new DebugArrayClosure(null, constantsAndNestedLambdas, nestedLambdaExpr);
 1832
 1833            var closurePlusParamTypes = RentPooledOrNewClosureTypeToParamTypes(nestedLambdaParamExprs);
 1834
 1835            var method = new DynamicMethod(string.Empty, nestedReturnType, closurePlusParamTypes, typeof(ArrayClosure), 
 1836            var il = DynamicMethodHacks.RentPooledOrNewILGenerator(method, nestedReturnType, closurePlusParamTypes);
 1837
 1838            if (constantsAndNestedLambdas != null)
 1839                EmittingVisitor.EmitLoadConstantsAndNestedLambdasIntoVars(il, ref nestedClosureInfo);
 1840
 1841            var parent = nestedReturnType == typeof(void) ? ParentFlags.IgnoreResult : ParentFlags.LambdaCall;
 1842            if (nestedReturnType.IsByRef)
 1843                parent |= ParentFlags.ReturnByRef;
 1844
 1845            var emitOk = EmittingVisitor.TryEmit(nestedLambdaBody, nestedLambdaParamExprs, il, ref nestedClosureInfo, fl
 1846            if (emitOk)
 1847            {
 1848                il.Demit(OpCodes.Ret);
 1849
 1850                // If we don't have closure then create a static or an open delegate to pass closure later in `TryEmitNe
 1851                // constructing the new closure with NonPassedParams and the rest of items stored in NestedLambdaWithCon
 1852                var nestedLambda = nestedLambdaClosure != null
 1853                    ? method.CreateDelegate(nestedLambdaExpr.Type, nestedLambdaClosure)
 1854                    : method.CreateDelegate(Tools.GetFuncOrActionType(closurePlusParamTypes, nestedReturnType), null);
 1855
 1856                nestedLambdaInfo.Lambda = !hasNonPassedParameters
 1857                    ? nestedLambda
 1858                    : !hasDebugInfo
 1859                        ? constantsAndNestedLambdas == null
 1860                            ? new NestedLambdaForNonPassedParams(nestedLambda)
 1861                            : new NestedLambdaForNonPassedParamsWithConstants(nestedLambda, constantsAndNestedLambdas)
 1862                        : new NestedLambdaForNonPassedParamsWithConstantsWithDebugInfo(nestedLambda, constantsAndNestedL
 1863
 1864                if (hasDebugInfo)
 1865                {
 1866                    var ilInstructions = nestedLambda.Method.ReadAllInstructions();
 1867                    if (nestedLambdaClosure is DebugArrayClosure debugInfoClosure)
 1868                        debugInfoClosure.ILInstructions = ilInstructions;
 1869                    else
 1870                        ((NestedLambdaForNonPassedParamsWithConstantsWithDebugInfo)nestedLambdaInfo.Lambda).ILInstructio
 1871                }
 1872            }
 1873            DynamicMethodHacks.FreePooledILGenerator(method, il);
 1874            FreePooledClosureTypeAndParamTypes(closurePlusParamTypes);
 1875            return emitOk;
 1876        }
 1877
 1878        /// <summary>Return IDelegateDebugInfo if the delegate is fast compiled with `CompilerFlags.EnableDelegateDebugI
 1879        public static IDelegateDebugInfo TryGetDebugInfo<TDelegate>(this TDelegate d)
 1880            where TDelegate : Delegate => d?.Target as IDelegateDebugInfo;
 1881
 1882#if LIGHT_EXPRESSION
 1883        private static Result TryCollectMemberInitExprConstants(ref ClosureInfo closure, MemberInitExpression expr,
 1884            IParameterProvider paramExprs, NestedLambdaInfo nestedLambda, ref SmallList<NestedLambdaInfo> rootNestedLamb
 1885        {
 1886            var newExpr = expr.Expression;
 1887            var binds = (IArgumentProvider<MemberBinding>)expr;
 1888            var count = binds.ArgumentCount;
 1889#else
 1890        private static Result TryCollectMemberInitExprConstants(ref ClosureInfo closure, MemberInitExpression expr,
 1891            IReadOnlyList<PE> paramExprs, NestedLambdaInfo nestedLambda, ref SmallList<NestedLambdaInfo> rootNestedLambd
 1892        {
 1893            var newExpr = expr.NewExpression;
 1894            var binds = expr.Bindings;
 1895            var count = binds.Count;
 1896#endif
 1897            var r = Result.OK;
 1898            if ((r = TryCollectInfo(ref closure, newExpr, paramExprs, nestedLambda, ref rootNestedLambdas, flags)) != Re
 1899                return r;
 1900
 1901            for (var i = 0; i < count; ++i)
 1902            {
 1903                var b = binds.GetArgument(i);
 1904                if (b.BindingType != MemberBindingType.Assignment)
 1905                    return b.BindingType == MemberBindingType.MemberBinding ? Result.NotSupported_MemberInit_MemberBindi
 1906
 1907                if ((r = TryCollectInfo(ref closure, ((MemberAssignment)b).Expression, paramExprs, nestedLambda, ref roo
 1908                    return r;
 1909            }
 1910            return r;
 1911        }
 1912
 1913        private static Result TryCollectListInitExprConstants(ref ClosureInfo closure, ListInitExpression expr,
 1914#if LIGHT_EXPRESSION
 1915            IParameterProvider paramExprs,
 1916#else
 1917            IReadOnlyList<PE> paramExprs,
 1918#endif
 1919            NestedLambdaInfo nestedLambda, ref SmallList<NestedLambdaInfo> rootNestedLambdas, CompilerFlags flags)
 1920        {
 1921            var newExpr = expr.NewExpression;
 1922            var inits = expr.Initializers;
 1923            var count = inits.Count;
 1924
 1925            var r = Result.OK;
 1926            if ((r = TryCollectInfo(ref closure, newExpr, paramExprs, nestedLambda, ref rootNestedLambdas, flags)) != Re
 1927                return r;
 1928
 1929            for (var i = 0; i < count; ++i)
 1930            {
 1931                var elemInit = inits.GetArgument(i);
 1932                var args = elemInit.Arguments;
 1933                var argCount = args.Count;
 1934                for (var a = 0; a < argCount; ++a)
 1935                    if ((r = TryCollectInfo(ref closure, args.GetArgument(a), paramExprs, nestedLambda, ref rootNestedLa
 1936                        return r;
 1937            }
 1938            return r;
 1939        }
 1940
 1941        private static Result TryCollectTryExprInfo(ref ClosureInfo closure, TryExpression tryExpr,
 1942#if LIGHT_EXPRESSION
 1943            IParameterProvider paramExprs,
 1944#else
 1945            IReadOnlyList<PE> paramExprs,
 1946#endif
 1947            NestedLambdaInfo nestedLambda, ref SmallList<NestedLambdaInfo> rootNestedLambdas, CompilerFlags flags)
 1948        {
 1949            var r = Result.OK;
 1950            if ((r = TryCollectInfo(ref closure, tryExpr.Body, paramExprs, nestedLambda, ref rootNestedLambdas, flags)) 
 1951                return r;
 1952
 1953            var catchBlocks = tryExpr.Handlers;
 1954            for (var i = 0; i < catchBlocks.Count; i++)
 1955            {
 1956                var catchBlock = catchBlocks[i];
 1957                var catchExVar = catchBlock.Variable;
 1958                if (catchExVar != null)
 1959                {
 1960                    closure.PushBlockWithVars(catchExVar);
 1961                    if ((r = TryCollectInfo(ref closure, catchExVar, paramExprs, nestedLambda, ref rootNestedLambdas, fl
 1962                        return r;
 1963                }
 1964
 1965                if (catchBlock.Filter != null &&
 1966                    (r = TryCollectInfo(ref closure, catchBlock.Filter, paramExprs, nestedLambda, ref rootNestedLambdas,
 1967                    return r;
 1968
 1969                if ((r = TryCollectInfo(ref closure, catchBlock.Body, paramExprs, nestedLambda, ref rootNestedLambdas, f
 1970                    return r;
 1971
 1972                if (catchExVar != null)
 1973                    closure.PopBlock();
 1974            }
 1975
 1976            var faultOrFinally = tryExpr.Fault ?? tryExpr.Finally;
 1977            if (faultOrFinally != null &&
 1978                (r = TryCollectInfo(ref closure, faultOrFinally, paramExprs, nestedLambda, ref rootNestedLambdas, flags)
 1979                return r;
 1980
 1981            return r;
 1982        }
 1983
 1984        #endregion
 1985
 1986        /// The minimal context-aware flags set by parent
 1987        [Flags]
 1988        internal enum ParentFlags
 1989        {
 1990            /// Default is no flags
 1991            Empty = 0,
 1992            /// The result of expression is ignored and maybe popped out
 1993            IgnoreResult = 1 << 1,
 1994            /// Some parent is the call expression
 1995            Call = 1 << 2,
 1996            /// Any Parent Expression is a MemberExpression
 1997            MemberAccess = 1 << 3,
 1998            /// Some arithmetic operation
 1999            Arithmetic = 1 << 4,
 2000            /// Subject
 2001            Coalesce = 1 << 5,
 2002            /// Expression with instance object (method call or member access or array access)
 2003            InstanceAccess = 1 << 6,
 2004            /// Subject
 2005            DupIt = 1 << 7,
 2006            /// Subject
 2007            TryCatch = 1 << 8,
 2008            /// Combination`of InstanceAccess and Call
 2009            InstanceCall = Call | InstanceAccess,
 2010            /// Constructor
 2011            Ctor = 1 << 9,
 2012            /// Constructor call
 2013            CtorCall = Call | Ctor,
 2014            /// Indexer
 2015            IndexAccess = 1 << 10,
 2016            /// Invoking the inlined lambda (the default System.Expression behavior)
 2017            InlinedLambdaInvoke = 1 << 11,
 2018            /// <summary>Indicate if the part AT LEAST participates in the assignment on the left side,
 2019            /// it may also participate in the right side, e.g. ++x.Bar</summary>
 2020            AssignmentLeftValue = 1 << 12,
 2021            /// <summary>Indicates the ONLY right value of assignment, e.g. `p` in `foo.Bar += p` </summary>
 2022            AssignmentRightValue = 1 << 13,
 2023            /// <summary>Assigning the ref of the right value to the left, e.g. in `var a = ref b[1]` we are passing thi
 2024            AssignmentByRef = 1 << 14,
 2025            /// <summary>Indicates the root lambda call</summary>
 2026            LambdaCall = 1 << 15,
 2027            /// <summary>ReturnByRef</summary>
 2028            ReturnByRef = 1 << 16,
 2029            /// <summary>The block result</summary>
 2030            BlockResult = 1 << 17,
 2031        }
 2032
 2033        [MethodImpl((MethodImplOptions)256)]
 2034        public static bool IgnoresResult(this ParentFlags parent) => (parent & ParentFlags.IgnoreResult) != 0;
 2035
 2036        [MethodImpl((MethodImplOptions)256)]
 2037        internal static bool EmitPopIfIgnoreResult(this ILGenerator il, ParentFlags parent)
 2038        {
 2039            if ((parent & ParentFlags.IgnoreResult) != 0)
 2040                il.Demit(OpCodes.Pop);
 2041            return true;
 2042        }
 2043
 2044        [MethodImpl((MethodImplOptions)256)]
 2045        internal static bool TryEmitBoxOf(this ILGenerator il, Type sourceType)
 2046        {
 2047            if (sourceType.IsValueType)
 2048                il.Demit(OpCodes.Box, sourceType);
 2049            return true;
 2050        }
 2051
 2052        [MethodImpl((MethodImplOptions)256)]
 2053        internal static bool TryEmitUnboxOf(this ILGenerator il, Type sourceType)
 2054        {
 2055            if (sourceType.IsValueType)
 2056                il.Demit(OpCodes.Unbox_Any, sourceType);
 2057            return true;
 2058        }
 2059
 2060        /// <summary>Supports emitting of selected expressions, e.g. lambdaExpr are not supported yet.
 2061        /// When emitter find not supported expression it will return false from <see cref="TryEmit"/>, so I could fallb
 2062        /// to normal and slow Expression.Compile.</summary>
 2063        [RequiresUnreferencedCode(Trimming.Message)]
 2064        internal static class EmittingVisitor
 2065        {
 2066            // todo: @perf use UnsafeAccessAttribute
 2067            /// <summary>Get a type from handle</summary>
 2068            public static readonly MethodInfo GetTypeFromHandleMethod =
 2069                ((Func<RuntimeTypeHandle, Type>)Type.GetTypeFromHandle).Method;
 2070            private static readonly MethodInfo _objectEqualsMethod =
 2071                ((Func<object, object, bool>)object.Equals).Method;
 2072
 2073            public static bool TryEmit(Expression expr,
 2074#if LIGHT_EXPRESSION
 2075                IParameterProvider paramExprs,
 2076#else
 2077                IReadOnlyList<PE> paramExprs,
 2078#endif
 2079                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent, int byRefIndex = -1)
 2080            {
 2081                var exprType = expr.Type;
 2082                while (true)
 2083                {
 2084                    closure.LastEmitIsAddress = false;
 2085#if LIGHT_EXPRESSION
 2086                    if (expr.IsIntrinsic)
 2087                        return expr.TryEmit(setup, ref closure, paramExprs, il, parent, byRefIndex);
 2088#endif
 2089                    var nodeType = expr.NodeType;
 2090                    switch (nodeType)
 2091                    {
 2092                        case ExpressionType.Parameter:
 2093                            return (parent & ParentFlags.IgnoreResult) != 0 ||
 2094                                TryEmitParameter((ParameterExpression)expr, paramExprs, il, ref closure, setup, parent, 
 2095
 2096                        case ExpressionType.TypeAs:
 2097                        case ExpressionType.IsTrue:
 2098                        case ExpressionType.IsFalse:
 2099                        case ExpressionType.Increment:
 2100                        case ExpressionType.Decrement:
 2101                        case ExpressionType.Negate:
 2102                        case ExpressionType.NegateChecked:
 2103                        case ExpressionType.OnesComplement:
 2104                        case ExpressionType.UnaryPlus:
 2105                        case ExpressionType.Unbox:
 2106                            return TryEmitSimpleUnaryExpression((UnaryExpression)expr, nodeType, paramExprs, il, ref clo
 2107
 2108                        case ExpressionType.TypeIs:
 2109                        case ExpressionType.TypeEqual:
 2110                            return TryEmitTypeIsOrEqual((TypeBinaryExpression)expr, paramExprs, il, ref closure, setup, 
 2111
 2112                        case ExpressionType.Convert:
 2113                        case ExpressionType.ConvertChecked:
 2114                            return TryEmitConvert((UnaryExpression)expr, paramExprs, il, ref closure, setup, parent);
 2115
 2116                        case ExpressionType.ArrayIndex:
 2117                            var arrIndexExpr = (BinaryExpression)expr;
 2118                            return TryEmit(arrIndexExpr.Left, paramExprs, il, ref closure, setup, parent | ParentFlags.I
 2119                                && TryEmit(arrIndexExpr.Right, paramExprs, il, ref closure, setup, parent | ParentFlags.
 2120                                && TryEmitArrayIndexGet(il, exprType, ref closure, parent);
 2121
 2122                        case ExpressionType.ArrayLength:
 2123                            if (!TryEmit(((UnaryExpression)expr).Operand, paramExprs, il, ref closure, setup, parent))
 2124                                return false;
 2125                            if ((parent & ParentFlags.IgnoreResult) == 0)
 2126                                il.Demit(OpCodes.Ldlen);
 2127                            return true;
 2128
 2129                        case ExpressionType.Constant:
 2130                            return (parent & ParentFlags.IgnoreResult) != 0 ||
 2131                                TryEmitConstant((ConstantExpression)expr, exprType, il, ref closure, byRefIndex);
 2132
 2133                        case ExpressionType.Call:
 2134                            return TryEmitMethodCall(expr, paramExprs, il, ref closure, setup, parent, byRefIndex);
 2135
 2136                        case ExpressionType.MemberAccess:
 2137                            return TryEmitMemberGet((MemberExpression)expr, paramExprs, il, ref closure, setup, parent, 
 2138
 2139                        case ExpressionType.New:
 2140                            return TryEmitNew(expr, paramExprs, il, ref closure, setup, parent);
 2141
 2142                        case ExpressionType.NewArrayBounds:
 2143                            return EmitNewArrayBounds((NewArrayExpression)expr, paramExprs, il, ref closure, setup, pare
 2144
 2145                        case ExpressionType.NewArrayInit:
 2146                            return EmitNewArrayInit((NewArrayExpression)expr, paramExprs, il, ref closure, setup, parent
 2147
 2148                        case ExpressionType.MemberInit:
 2149                            return EmitMemberInit((MemberInitExpression)expr, paramExprs, il, ref closure, setup, parent
 2150
 2151                        case ExpressionType.ListInit:
 2152                            return TryEmitListInit((ListInitExpression)expr, paramExprs, il, ref closure, setup, parent)
 2153
 2154                        case ExpressionType.Lambda:
 2155                            return TryEmitNestedLambda((LambdaExpression)expr, paramExprs, il, ref closure);
 2156
 2157                        case ExpressionType.Invoke:
 2158                            return TryEmitInvoke((InvocationExpression)expr, paramExprs, il, ref closure, setup, parent)
 2159
 2160                        case ExpressionType.GreaterThan:
 2161                        case ExpressionType.GreaterThanOrEqual:
 2162                        case ExpressionType.LessThan:
 2163                        case ExpressionType.LessThanOrEqual:
 2164                        case ExpressionType.Equal:
 2165                        case ExpressionType.NotEqual:
 2166                            {
 2167                                if (exprType.IsPrimitive && Interpreter.TryInterpretBool(out var boolResult, expr, setup
 2168                                {
 2169                                    if ((parent & ParentFlags.IgnoreResult) == 0)
 2170                                        il.Demit(boolResult ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
 2171                                    return true;
 2172                                }
 2173                                return TryEmitComparison(((BinaryExpression)expr).Left, ((BinaryExpression)expr).Right, 
 2174                                    ref closure, setup, parent);
 2175                            }
 2176                        case ExpressionType.Add:
 2177                        case ExpressionType.Subtract:
 2178                        case ExpressionType.Multiply:
 2179                        case ExpressionType.Divide:
 2180                        case ExpressionType.Modulo:
 2181                        case ExpressionType.And:
 2182                        case ExpressionType.Or:
 2183                        case ExpressionType.ExclusiveOr:
 2184                        case ExpressionType.LeftShift:
 2185                        case ExpressionType.RightShift:
 2186                            {
 2187                                return exprType.IsPrimitive
 2188                                    && TryInterpretAndEmitResult(expr, il, parent, setup)
 2189                                    || TryEmitArithmetic(((BinaryExpression)expr).Left, ((BinaryExpression)expr).Right, 
 2190                                        ref closure, setup, parent);
 2191                            }
 2192                        // todo: @feature #472 add interpretation when those node types are supported
 2193                        case ExpressionType.AddChecked:
 2194                        case ExpressionType.SubtractChecked:
 2195                        case ExpressionType.MultiplyChecked:
 2196                        case ExpressionType.Power:
 2197                            return TryEmitArithmetic(((BinaryExpression)expr).Left, ((BinaryExpression)expr).Right, node
 2198                                ref closure, setup, parent);
 2199
 2200                        case ExpressionType.AndAlso:
 2201                        case ExpressionType.OrElse:
 2202                            {
 2203                                if (Interpreter.TryInterpretBool(out var resultBool, expr, setup))
 2204                                {
 2205                                    if ((parent & ParentFlags.IgnoreResult) == 0)
 2206                                        il.Demit(resultBool ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
 2207                                    return true;
 2208                                }
 2209                                return TryEmitLogicalOperator((BinaryExpression)expr, nodeType, paramExprs, il, ref clos
 2210                            }
 2211                        case ExpressionType.Not:
 2212                            {
 2213                                if (Interpreter.TryInterpretBool(out var resultBool, expr, setup))
 2214                                {
 2215                                    if ((parent & ParentFlags.IgnoreResult) == 0)
 2216                                        il.Demit(resultBool ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
 2217                                    return true;
 2218                                }
 2219                                return TryEmitNot((UnaryExpression)expr, paramExprs, il, ref closure, setup, parent);
 2220                            }
 2221                        case ExpressionType.Coalesce:
 2222                            return TryEmitCoalesceOperator((BinaryExpression)expr, paramExprs, il, ref closure, setup, p
 2223
 2224                        case ExpressionType.Conditional:
 2225                            var condExpr = (ConditionalExpression)expr;
 2226                            var testExpr = condExpr.Test;
 2227                            if (Interpreter.TryInterpretBool(out var testIsTrue, testExpr, setup))
 2228                            {
 2229                                expr = testIsTrue ? condExpr.IfTrue : condExpr.IfFalse;
 2230                                continue; // no recursion, just continue with the left or right side of condition
 2231                            }
 2232                            return TryEmitConditional(testExpr, condExpr.IfTrue, condExpr.IfFalse, paramExprs, il, ref c
 2233
 2234                        case ExpressionType.PostIncrementAssign:
 2235                        case ExpressionType.PreIncrementAssign:
 2236                            return TryEmitArithmeticAndOrAssign(((UnaryExpression)expr).Operand, null, exprType, Express
 2237                                nodeType == ExpressionType.PostIncrementAssign, paramExprs, il, ref closure, setup, pare
 2238
 2239                        case ExpressionType.PostDecrementAssign:
 2240                        case ExpressionType.PreDecrementAssign:
 2241                            return TryEmitArithmeticAndOrAssign(((UnaryExpression)expr).Operand, null, exprType, Express
 2242                                nodeType == ExpressionType.PostDecrementAssign, paramExprs, il, ref closure, setup, pare
 2243
 2244                        case ExpressionType.AddAssign:
 2245                        case ExpressionType.AddAssignChecked:
 2246                        case ExpressionType.SubtractAssign:
 2247                        case ExpressionType.SubtractAssignChecked:
 2248                        case ExpressionType.MultiplyAssign:
 2249                        case ExpressionType.MultiplyAssignChecked:
 2250                        case ExpressionType.DivideAssign:
 2251                        case ExpressionType.ModuloAssign:
 2252                        case ExpressionType.PowerAssign:
 2253                        case ExpressionType.AndAssign:
 2254                        case ExpressionType.OrAssign:
 2255                        case ExpressionType.ExclusiveOrAssign:
 2256                        case ExpressionType.LeftShiftAssign:
 2257                        case ExpressionType.RightShiftAssign:
 2258                        case ExpressionType.Assign:
 2259                            var ba = (BinaryExpression)expr;
 2260                            return TryEmitArithmeticAndOrAssign(ba.Left, ba.Right, exprType,
 2261                                AssignToArithmeticOrSelf(nodeType), false, paramExprs, il, ref closure, setup, parent);
 2262
 2263                        case ExpressionType.Block:
 2264                            {
 2265                                var blockExpr = (BlockExpression)expr;
 2266                                var blockVarExprs = blockExpr.Variables;
 2267                                var blockVarCount = blockVarExprs?.Count ?? 0;
 2268                                var statementExprs = blockExpr.Expressions; // Trim the expressions after the Throw - #1
 2269                                var statementCount = statementExprs.Count;
 2270                                if (statementCount == 0)
 2271                                    return true; // yeah, it is a valid thing
 2272
 2273                                if (blockVarCount == 1 & statementCount == 2 &&
 2274                                    statementExprs[0] is BinaryExpression st0 && st0.NodeType == ExpressionType.Assign &
 2275                                    statementExprs[1] is BinaryExpression st1 && st1.NodeType == ExpressionType.Assign &
 2276                                    st0.Left == blockVarExprs[0] && st1.Right == blockVarExprs[0])
 2277                                    return TryEmitArithmeticAndOrAssign(st1.Left, st0.Right, st0.Left.Type,
 2278                                        ExpressionType.Assign, false, paramExprs, il, ref closure, setup, parent);
 2279
 2280                                if (blockVarCount != 0)
 2281                                    closure.PushBlockAndConstructLocalVars(blockVarExprs, il);
 2282
 2283                                expr = statementExprs[statementCount - 1]; // The last (result) statement in block will 
 2284
 2285                                // Try to trim the statements from the end of the Block up to the Throw (if any),
 2286                                // or to the prior Label as in the #442 case 2
 2287                                if (statementCount > 1)
 2288                                {
 2289                                    var throwIndex = statementCount - 1;
 2290                                    for (; throwIndex != -1; --throwIndex)
 2291                                    {
 2292                                        var se = statementExprs[throwIndex];
 2293                                        if (se.NodeType == ExpressionType.Label)
 2294                                        {
 2295                                            throwIndex = -1; // stop the search
 2296                                            break;
 2297                                        }
 2298                                        if (se.NodeType == ExpressionType.Throw)
 2299                                            break;
 2300                                    }
 2301
 2302                                    // If we have a Throw and it is not the last one
 2303                                    if (throwIndex != -1 && throwIndex != statementCount - 1)
 2304                                    {
 2305                                        // Change the Throw return type to match the one for the Block, and adjust the s
 2306                                        expr = Expression.Throw(((UnaryExpression)statementExprs[throwIndex]).Operand, b
 2307                                        statementCount = throwIndex + 1;
 2308                                    }
 2309                                }
 2310
 2311                                // handle the all statements in block excluding the last one
 2312                                if (statementCount > 1)
 2313                                {
 2314                                    for (var i = 0; i < statementCount - 1; i++)
 2315                                    {
 2316                                        var stExpr = statementExprs[i];
 2317                                        if (stExpr.NodeType == ExpressionType.Default && stExpr.Type == typeof(void))
 2318                                            continue;
 2319
 2320                                        // This is basically the return pattern (see #237), so we don't care for the res
 2321                                        if (stExpr is GotoExpression gt && gt.Kind == GotoExpressionKind.Return &&
 2322                                            statementExprs[i + 1] is LabelExpression label && label.Target == gt.Target)
 2323                                        {
 2324                                            // But we cannot use the return pattern and eliminate the target label if we
 2325                                            var (gotos, labels) = closure.TargetToGotosAndLabels.Map.TryGetValueRef(labe
 2326                                            if (found && gotos <= labels)
 2327                                            {
 2328                                                if ((parent & ParentFlags.TryCatch) != 0)
 2329                                                {
 2330                                                    if ((setup & CompilerFlags.ThrowOnNotSupportedExpression) != 0)
 2331                                                        throw new NotSupportedExpressionException(Result.NotSupported_Tr
 2332                                                    return false; // todo: @feature return from the TryCatch with the in
 2333                                                }
 2334
 2335                                                // we are generating the return value and ensuring here that it is not p
 2336                                                var gtOrLabelValue = gt.Value ?? label.DefaultValue;
 2337                                                if (gtOrLabelValue != null)
 2338                                                {
 2339                                                    if (!TryEmit(gtOrLabelValue, paramExprs, il, ref closure, setup, par
 2340                                                        return false;
 2341
 2342                                                    if ((parent & ParentFlags.InlinedLambdaInvoke) != 0)
 2343                                                    {
 2344                                                        ref var foundLabel = ref closure.LambdaInvokeStackLabels.GetLabe
 2345                                                        if (!labelFound || foundLabel.InlinedLambdaInvokeIndex == -1)
 2346                                                            return false;
 2347                                                        EmitGotoToReturnLabel(ref closure.LambdaInvokeStackLabels.GetSur
 2348                                                    }
 2349                                                    else
 2350                                                    {
 2351                                                        // @hack (related to #237) if `IgnoreResult` set, that means the
 2352                                                        // emitting the double `OpCodes.Ret` (usually for not the last s
 2353                                                        // And vice-versa, if `IgnoreResult` not set then the external c
 2354                                                        // so we should avoid it on our side.
 2355                                                        if ((parent & ParentFlags.IgnoreResult) != 0)
 2356                                                            il.Demit(OpCodes.Ret);
 2357                                                    }
 2358                                                }
 2359                                                return true;
 2360                                            }
 2361                                        }
 2362
 2363                                        if (!TryEmit(stExpr, paramExprs, il, ref closure, setup, parent | ParentFlags.Ig
 2364                                            return false;
 2365                                    }
 2366                                }
 2367
 2368                                parent |= ParentFlags.BlockResult;
 2369                                if (blockVarCount == 0)
 2370                                    continue; // OMG! no recursion, continue with the last expression
 2371
 2372                                if (!TryEmit(expr, paramExprs, il, ref closure, setup, parent))
 2373                                    return false;
 2374
 2375                                closure.PopBlock();
 2376                                return true;
 2377                            }
 2378                        case ExpressionType.Loop:
 2379                            return TryEmitLoop((LoopExpression)expr, paramExprs, il, ref closure, setup, parent);
 2380
 2381                        case ExpressionType.Try:
 2382                            return TryEmitTryCatchFinallyBlock((TryExpression)expr, paramExprs, il, ref closure, setup, 
 2383
 2384                        case ExpressionType.Throw:
 2385                            {
 2386                                var ok = true;
 2387                                var throwOperand = ((UnaryExpression)expr).Operand;
 2388                                if (throwOperand != null)
 2389                                    ok = TryEmit(throwOperand, paramExprs, il, ref closure, setup, parent & ~ParentFlags
 2390                                il.Demit(throwOperand != null ? OpCodes.Throw : OpCodes.Rethrow);
 2391                                return ok;
 2392                            }
 2393
 2394                        case ExpressionType.Default:
 2395                            if (exprType != typeof(void) && (parent & ParentFlags.IgnoreResult) == 0)
 2396                                EmitDefault(il, exprType);
 2397                            return true;
 2398
 2399                        case ExpressionType.Index:
 2400                            return TryEmitIndexGet((IndexExpression)expr, paramExprs, il, ref closure, setup, parent);
 2401
 2402                        case ExpressionType.Goto:
 2403                            return TryEmitGoto((GotoExpression)expr, paramExprs, il, ref closure, setup, parent);
 2404
 2405                        case ExpressionType.Label:
 2406                            return TryEmitLabel((LabelExpression)expr, paramExprs, il, ref closure, setup, parent);
 2407
 2408                        case ExpressionType.Switch:
 2409                            return TryEmitSwitch((SwitchExpression)expr, paramExprs, il, ref closure, setup, parent);
 2410
 2411                        case ExpressionType.Extension:
 2412                            expr = expr.Reduce();
 2413                            continue;
 2414
 2415                        case ExpressionType.DebugInfo: // todo: @feature - is not supported yet
 2416                            return true;               // todo: @unclear - just ignoring the info for now
 2417
 2418                        case ExpressionType.Quote:     // todo: @feature - is not supported yet
 2419                        default:
 2420                            return false;
 2421
 2422                    }
 2423                }
 2424            }
 2425
 2426#if LIGHT_EXPRESSION
 2427            private static bool TryEmitNew(Expression expr, IParameterProvider paramExprs, ILGenerator il, ref ClosureIn
 2428                CompilerFlags setup, ParentFlags parent)
 2429#else
 2430            private static bool TryEmitNew(Expression expr, IReadOnlyList<PE> paramExprs, ILGenerator il, ref ClosureInf
 2431                CompilerFlags setup, ParentFlags parent)
 2432#endif
 2433            {
 2434                parent |= ParentFlags.CtorCall;
 2435                var newExpr = (NewExpression)expr;
 2436#if SUPPORTS_ARGUMENT_PROVIDER
 2437                var argExprs = (IArgumentProvider)newExpr;
 2438#else
 2439                var argExprs = newExpr.Arguments;
 2440#endif
 2441                var argCount = argExprs.GetCount();
 2442                var ctor = newExpr.Constructor;
 2443                if (argCount != 0)
 2444                {
 2445                    var pars = ctor.GetParameters();
 2446
 2447                    // If we have complex arguments then it is better to store them in the variables, then load them bef
 2448                    // Otherwise the stack may be broken by the long emit chain, and the previous argument result on sta
 2449                    // may be hidden by the next argument interim stack additions,
 2450                    // see the #488 for the details.
 2451                    if (argCount == 1)
 2452                    {
 2453                        if (!TryEmit(argExprs.GetArgument(0), paramExprs, il, ref closure, setup, parent, pars[0].Parame
 2454                            return false;
 2455                    }
 2456                    else
 2457                    {
 2458                        if (!closure.ArgsContainingComplexExpression.Map.ContainsKey(newExpr))
 2459                        {
 2460                            for (var i = 0; i < argCount; ++i)
 2461                                if (!TryEmit(argExprs.GetArgument(i), paramExprs, il, ref closure, setup, parent, pars[i
 2462                                    return false;
 2463                        }
 2464                        else
 2465                        {
 2466                            SmallList<int, Stack8<int>> argVars = default;
 2467                            for (var i = 0; i < argCount; ++i)
 2468                            {
 2469                                var argExpr = argExprs.GetArgument(i);
 2470                                var parType = pars[i].ParameterType;
 2471                                if (!TryEmit(argExpr, paramExprs, il, ref closure, setup, parent, parType.IsByRef ? i : 
 2472                                    return false;
 2473                                argVars.Add(EmitStoreLocalVariable(il, parType));
 2474                            }
 2475                            for (var i = 0; i < argCount; ++i)
 2476                                EmitLoadLocalVariable(il, argVars[i]);
 2477                        }
 2478                    }
 2479                }
 2480                // ReSharper disable once ConditionIsAlwaysTrueOrFalse
 2481                if (ctor != null)
 2482                    il.Demit(OpCodes.Newobj, ctor);
 2483                else if (newExpr.Type.IsValueType)
 2484                {
 2485                    ctor = newExpr.Type.GetConstructor(
 2486                        BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
 2487                        default, CallingConventions.Any, Tools.Empty<Type>(), default);
 2488                    if (ctor != null)
 2489                        il.Demit(OpCodes.Newobj, ctor);
 2490                    else
 2491                        EmitLoadLocalVariable(il, InitValueTypeVariable(il, newExpr.Type));
 2492                }
 2493                else
 2494                    return false;
 2495                return true;
 2496            }
 2497
 2498#if LIGHT_EXPRESSION
 2499            private static bool TryEmitLoop(LoopExpression loopExpr, IParameterProvider paramExprs, ILGenerator il, ref 
 2500                CompilerFlags setup, ParentFlags parent)
 2501#else
 2502            private static bool TryEmitLoop(LoopExpression loopExpr, IReadOnlyList<PE> paramExprs, ILGenerator il, ref C
 2503                CompilerFlags setup, ParentFlags parent)
 2504#endif
 2505            {
 2506                // Mark the start of the loop body:
 2507                var loopBodyLabel = il.DefineLabel();
 2508                il.DmarkLabel(loopBodyLabel);
 2509
 2510                if (loopExpr.ContinueLabel != null)
 2511                {
 2512                    ref var continueLabelInfo = ref closure.LambdaInvokeStackLabels.GetLabelOrInvokeIndexByTarget(loopEx
 2513                    if (!foundLabel)
 2514                        return false;
 2515                    var continueLabel = continueLabelInfo.GetOrDefineLabel(il);
 2516                    il.DmarkLabel(continueLabel);
 2517                }
 2518
 2519                if (!TryEmit(loopExpr.Body, paramExprs, il, ref closure, setup, parent))
 2520                    return false;
 2521
 2522                // If loop hasn't exited, jump back to start of its body:
 2523                il.Demit(OpCodes.Br, loopBodyLabel);
 2524
 2525                if (loopExpr.BreakLabel != null)
 2526                {
 2527                    ref var breakLabelInfo = ref closure.LambdaInvokeStackLabels.GetLabelOrInvokeIndexByTarget(loopExpr.
 2528                    if (!foundLabel)
 2529                        return false;
 2530                    var breakLabel = breakLabelInfo.GetOrDefineLabel(il);
 2531                    il.DmarkLabel(breakLabel);
 2532                }
 2533
 2534                return true;
 2535            }
 2536
 2537            // similar code is used by the TryEmitArithmeticAndOrAssign, so don't forget to modify it as well
 2538            private static bool TryEmitIndexGet(IndexExpression indexExpr,
 2539#if LIGHT_EXPRESSION
 2540                IParameterProvider paramExprs,
 2541#else
 2542                IReadOnlyList<PE> paramExprs,
 2543#endif
 2544                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 2545            {
 2546                var p = parent & ~ParentFlags.IgnoreResult | ParentFlags.IndexAccess;
 2547
 2548                var objExpr = indexExpr.Object;
 2549                if (objExpr != null &&
 2550                    !TryEmit(objExpr, paramExprs, il, ref closure, setup, p | ParentFlags.InstanceAccess))
 2551                    return false;
 2552
 2553#if SUPPORTS_ARGUMENT_PROVIDER
 2554                var indexArgs = (IArgumentProvider)indexExpr;
 2555#else
 2556                var indexArgs = indexExpr.Arguments;
 2557#endif
 2558                var indexArgCount = indexArgs.GetCount();
 2559                for (var i = 0; i < indexArgCount; i++)
 2560                    if (!TryEmit(indexArgs.GetArgument(i), paramExprs, il, ref closure, setup, p, -1))
 2561                        return false;
 2562
 2563                var indexerProp = indexExpr.Indexer;
 2564                return indexerProp != null
 2565                    ? EmitMethodCallOrVirtualCallCheckForNull(il, indexerProp.GetMethod)
 2566                    : indexArgCount == 1
 2567                        ? TryEmitArrayIndexGet(il, indexExpr.Type, ref closure, parent) // one-dimensional array
 2568                        : EmitMethodCallOrVirtualCallCheckForNull(il, objExpr?.Type.FindMethod("Get")); // multi-dimensi
 2569            }
 2570
 2571#if LIGHT_EXPRESSION
 2572            private static bool TryEmitLabel(LabelExpression expr, IParameterProvider paramExprs, ILGenerator il, ref Cl
 2573                CompilerFlags setup, ParentFlags parent)
 2574#else
 2575            private static bool TryEmitLabel(LabelExpression expr, IReadOnlyList<PE> paramExprs, ILGenerator il, ref Clo
 2576                CompilerFlags setup, ParentFlags parent)
 2577#endif
 2578            {
 2579                ref var labelInfo = ref closure.LambdaInvokeStackLabels.GetLabelOrInvokeIndexByTarget(expr.Target, out v
 2580                if (!foundLabel)
 2581                    return false;
 2582
 2583                var label = labelInfo.GetOrDefineLabel(il);
 2584                il.DmarkLabel(label);
 2585
 2586                var defaultValue = expr.DefaultValue;
 2587                if (defaultValue != null && !TryEmit(defaultValue, paramExprs, il, ref closure, setup, parent))
 2588                    return false;
 2589
 2590                var returnVariableIndexPlusOne = labelInfo.ReturnVariableIndexPlusOneAndIsDefined >>> 1;
 2591                if (returnVariableIndexPlusOne != 0)
 2592                {
 2593                    if (defaultValue != null)
 2594                        EmitStoreLocalVariable(il, returnVariableIndexPlusOne - 1);
 2595
 2596                    il.DmarkLabel(labelInfo.ReturnLabel);
 2597                    if (!parent.IgnoresResult())
 2598                        EmitLoadLocalVariable(il, returnVariableIndexPlusOne - 1);
 2599                }
 2600                return foundLabel;
 2601            }
 2602
 2603            // For TryCatch get the variable for saving the result from the LabelInfo store the return expression result
 2604            // Emit OpCodes.Leave or OpCodes.Br to the special label with the result which should be marked after the la
 2605            private static void EmitGotoToReturnLabel(ref LabelInfo labelInfo, ILGenerator il, Expression gotoValue, OpC
 2606            {
 2607                var returnVariableIndexPlusOne = labelInfo.ReturnVariableIndexPlusOneAndIsDefined >>> 1;
 2608                if (returnVariableIndexPlusOne == 0)
 2609                {
 2610                    returnVariableIndexPlusOne = il.GetNextLocalVarIndex(gotoValue.Type) + 1;
 2611                    labelInfo.ReturnVariableIndexPlusOneAndIsDefined = (short)(returnVariableIndexPlusOne << 1);
 2612                    labelInfo.ReturnLabel = il.DefineLabel();
 2613                }
 2614                EmitStoreLocalVariable(il, returnVariableIndexPlusOne - 1);
 2615                il.Demit(returnOpCode, labelInfo.ReturnLabel);
 2616            }
 2617
 2618#if LIGHT_EXPRESSION
 2619            private static bool TryEmitGoto(GotoExpression expr, IParameterProvider paramExprs, ILGenerator il, ref Clos
 2620                CompilerFlags setup, ParentFlags parent)
 2621#else
 2622            private static bool TryEmitGoto(GotoExpression expr, IReadOnlyList<PE> paramExprs, ILGenerator il, ref Closu
 2623                CompilerFlags setup, ParentFlags parent)
 2624#endif
 2625            {
 2626                ref var labelInfo = ref closure.LambdaInvokeStackLabels.GetLabelOrInvokeIndexByTarget(expr.Target, out v
 2627                if (!labelFound)
 2628                {
 2629                    if ((closure.Status & ClosureStatus.ToBeCollected) == 0)
 2630                        return false; // if no collection cycle then the labels may be not collected
 2631                    throw new InvalidOperationException($"Cannot jump, no labels found for the target `{expr.Target}`");
 2632                }
 2633                var gotoValue = expr.Value;
 2634                if (gotoValue != null &&
 2635                    !TryEmit(gotoValue, paramExprs, il, ref closure, setup, parent & ~ParentFlags.IgnoreResult))
 2636                    return false;
 2637
 2638                switch (expr.Kind)
 2639                {
 2640                    case GotoExpressionKind.Break:
 2641                    case GotoExpressionKind.Continue:
 2642                        il.Demit(OpCodes.Br, labelInfo.GetOrDefineLabel(il));
 2643                        return true;
 2644
 2645                    case GotoExpressionKind.Goto:
 2646                        if (gotoValue != null)
 2647                            goto case GotoExpressionKind.Return;
 2648
 2649                        var gotoOpCode = (parent & ParentFlags.TryCatch) != 0 ? OpCodes.Leave : OpCodes.Br;
 2650                        il.Demit(gotoOpCode, labelInfo.GetOrDefineLabel(il));
 2651                        return true;
 2652
 2653                    case GotoExpressionKind.Return:
 2654                        if ((parent & ParentFlags.TryCatch) != 0)
 2655                        {
 2656                            if (gotoValue != null)
 2657                                EmitGotoToReturnLabel(ref labelInfo, il, gotoValue, OpCodes.Leave);
 2658                            else
 2659                                il.Demit(OpCodes.Leave, labelInfo.GetOrDefineLabel(il)); // if there is no return value 
 2660                        }
 2661                        else if ((parent & ParentFlags.InlinedLambdaInvoke) != 0)
 2662                        {
 2663                            if (gotoValue != null)
 2664                            {
 2665                                var invokeIndex = labelInfo.InlinedLambdaInvokeIndex;
 2666                                if (invokeIndex == -1)
 2667                                    return false;
 2668                                EmitGotoToReturnLabel(ref closure.LambdaInvokeStackLabels.GetSurePresentItemRef(invokeIn
 2669                            }
 2670                        }
 2671                        else
 2672                            il.Demit(OpCodes.Ret);
 2673                        return true;
 2674
 2675                    default:
 2676                        return false;
 2677                }
 2678            }
 2679
 2680#if LIGHT_EXPRESSION
 2681            private static bool TryEmitCoalesceOperator(BinaryExpression expr, IParameterProvider paramExprs, ILGenerato
 2682                CompilerFlags setup, ParentFlags parent)
 2683#else
 2684            private static bool TryEmitCoalesceOperator(BinaryExpression expr, IReadOnlyList<PE> paramExprs, ILGenerator
 2685                CompilerFlags setup, ParentFlags parent)
 2686#endif
 2687            {
 2688                var labelFalse = il.DefineLabel(); // todo: @perf define only if needed
 2689                var labelDone = il.DefineLabel();
 2690
 2691                var left = expr.Left;
 2692                var right = expr.Right;
 2693
 2694                // we won't OpCodes.Pop inside the Coalesce as it may leave the Il in invalid state - instead we will po
 2695                var flags = (parent & ~ParentFlags.IgnoreResult) | ParentFlags.Coalesce;
 2696
 2697                if (!TryEmit(left, paramExprs, il, ref closure, setup, flags))
 2698                    return false;
 2699
 2700                var exprType = expr.Type;
 2701                var leftType = left.Type;
 2702                if (leftType.IsValueType)
 2703                {
 2704                    Debug.Assert(leftType.IsNullable(), "Expecting Nullable, it is the only ValueType comparable to null
 2705
 2706                    var varIndex = EmitStoreAndLoadLocalVariableAddress(il, leftType);
 2707                    EmitMethodCall(il, leftType.GetNullableHasValueGetterMethod());
 2708
 2709                    il.Demit(OpCodes.Brfalse, labelFalse);
 2710
 2711                    if (exprType == Nullable.GetUnderlyingType(leftType))
 2712                    {
 2713                        // if the target expression type is of underlying nullable, and the left operand is not null,
 2714                        // then extract its underlying value
 2715                        EmitLoadLocalVariableAddress(il, varIndex);
 2716                        il.Demit(OpCodes.Ldfld, leftType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod());
 2717                    }
 2718                    else
 2719                        EmitLoadLocalVariable(il, varIndex); // loading the value (not address) to return it
 2720
 2721                    il.Demit(OpCodes.Br, labelDone);
 2722                    il.DmarkLabel(labelFalse);
 2723                    if (!TryEmit(right, paramExprs, il, ref closure, setup, flags))
 2724                        return false;
 2725
 2726                    il.DmarkLabel(labelDone);
 2727                }
 2728                else
 2729                {
 2730                    il.Demit(OpCodes.Dup);                // duplicate left, if it's not null, after the branch this val
 2731                    il.Demit(OpCodes.Brtrue, labelFalse); // automates the chain of the Ldnull, Ceq, Brfalse
 2732                    il.Demit(OpCodes.Pop);                // left is null, pop its value from the stack
 2733
 2734                    if (!TryEmit(right, paramExprs, il, ref closure, setup, flags))
 2735                        return false;
 2736
 2737                    if (right.Type != exprType)
 2738                        il.TryEmitBoxOf(right.Type);
 2739
 2740                    if (left.Type == exprType)
 2741                        il.DmarkLabel(labelFalse);
 2742                    else
 2743                    {
 2744                        il.Demit(OpCodes.Br, labelDone);
 2745                        il.DmarkLabel(labelFalse); // todo: @bug? should we insert the boxing for the Nullable value typ
 2746                        il.Demit(OpCodes.Castclass, exprType);
 2747                        il.DmarkLabel(labelDone);
 2748                    }
 2749                }
 2750                return il.EmitPopIfIgnoreResult(parent);
 2751            }
 2752
 2753            /// <summary>Emit default op code for the type</summary>
 2754            public static void EmitDefault(ILGenerator il, Type type)
 2755            {
 2756                if (type.IsClass)
 2757                {
 2758                    il.Demit(OpCodes.Ldnull);
 2759                    return;
 2760                }
 2761                switch (Type.GetTypeCode(type))
 2762                {
 2763                    case TypeCode.Boolean:
 2764                    case TypeCode.Char:
 2765                    case TypeCode.Byte:
 2766                    case TypeCode.SByte:
 2767                    case TypeCode.Int16:
 2768                    case TypeCode.UInt16:
 2769                    case TypeCode.Int32:
 2770                    case TypeCode.UInt32:
 2771                        il.Demit(OpCodes.Ldc_I4_0);
 2772                        break;
 2773                    case TypeCode.Int64:
 2774                    case TypeCode.UInt64:
 2775                        il.Demit(OpCodes.Ldc_I4_0);
 2776                        il.Demit(OpCodes.Conv_I8);
 2777                        break;
 2778                    case TypeCode.Single:
 2779                        il.Demit(OpCodes.Ldc_R4, default(float));
 2780                        break;
 2781                    case TypeCode.Double:
 2782                        il.Demit(OpCodes.Ldc_R8, default(double));
 2783                        break;
 2784                    default:
 2785                        EmitLoadLocalVariable(il, InitValueTypeVariable(il, type));
 2786                        break;
 2787                }
 2788            }
 2789
 2790#if LIGHT_EXPRESSION
 2791            private static bool TryEmitTryCatchFinallyBlock(TryExpression tryExpr, IParameterProvider paramExprs, ILGene
 2792                CompilerFlags setup, ParentFlags parent)
 2793#else
 2794            private static bool TryEmitTryCatchFinallyBlock(TryExpression tryExpr, IReadOnlyList<PE> paramExprs, ILGener
 2795                CompilerFlags setup, ParentFlags parent)
 2796#endif
 2797            {
 2798#if DEMIT
 2799                Debug.WriteLine("try {");
 2800#endif
 2801                il.BeginExceptionBlock();
 2802
 2803                if (!TryEmit(tryExpr.Body, paramExprs, il, ref closure, setup, parent))
 2804                    return false;
 2805
 2806                var exprType = tryExpr.Type;
 2807                var returnsResult = exprType != typeof(void) && !parent.IgnoresResult();
 2808                var resultVarIndex = -1;
 2809
 2810                if (returnsResult)
 2811                    EmitStoreLocalVariable(il, resultVarIndex = il.GetNextLocalVarIndex(exprType));
 2812
 2813                var catchBlocks = tryExpr.Handlers;
 2814                for (var i = 0; i < catchBlocks.Count; i++)
 2815                {
 2816                    var catchBlock = catchBlocks[i];
 2817                    if (catchBlock.Filter != null)
 2818                    {
 2819                        if ((setup & CompilerFlags.ThrowOnNotSupportedExpression) != 0)
 2820                            throw new NotSupportedExpressionException(Result.NotSupported_ExceptionCatchFilter);
 2821                        return false;
 2822                    }
 2823
 2824                    il.BeginCatchBlock(catchBlock.Test);
 2825
 2826                    // at the beginning of catch the Exception value is on the stack,
 2827                    // we will store into local variable.
 2828                    var exVarExpr = catchBlock.Variable;
 2829#if DEMIT
 2830                    Debug.WriteLine($"}} catch {{");
 2831#endif
 2832                    if (exVarExpr != null)
 2833                    {
 2834                        // first, check if the exception variable was used before and supposed to be reused in the new c
 2835                        // (this is decided by creator of expression)
 2836                        var exVarIndex = closure.GetDefinedLocalVarOrDefault(exVarExpr);
 2837                        if (exVarIndex == -1)
 2838                            exVarIndex = il.GetNextLocalVarIndex(exVarExpr.Type);
 2839                        closure.PushBlockWithVars(exVarExpr, exVarIndex);
 2840                        EmitStoreLocalVariable(il, exVarIndex);
 2841                    }
 2842
 2843                    if (!TryEmit(catchBlock.Body, paramExprs, il, ref closure, setup, parent))
 2844                        return false;
 2845
 2846                    if (exVarExpr != null)
 2847                        closure.PopBlock();
 2848
 2849                    if (returnsResult)
 2850                        EmitStoreLocalVariable(il, resultVarIndex);
 2851                }
 2852
 2853                if (tryExpr.Fault != null)
 2854                {
 2855                    var faultExpr = tryExpr.Fault;
 2856#if DEMIT
 2857                    Debug.WriteLine("} fault {" + faultExpr);
 2858#endif
 2859                    il.BeginFaultBlock();
 2860                    // it is important to ignore result for the fault block, because it should not return anything
 2861                    if (!TryEmit(faultExpr, paramExprs, il, ref closure, setup, parent | ParentFlags.IgnoreResult))
 2862                        return false;
 2863                }
 2864                else if (tryExpr.Finally != null)
 2865                {
 2866                    var finallyExpr = tryExpr.Finally;
 2867#if DEMIT
 2868                    Debug.WriteLine("} finally {" + finallyExpr);
 2869#endif
 2870                    il.BeginFinallyBlock();
 2871                    // it is important to ignore result for the finally block, because it should not return anything
 2872                    if (!TryEmit(finallyExpr, paramExprs, il, ref closure, setup, parent | ParentFlags.IgnoreResult))
 2873                        return false;
 2874                }
 2875
 2876                il.EndExceptionBlock();
 2877
 2878#if DEMIT
 2879                Debug.WriteLine("}");
 2880#endif
 2881
 2882                if (returnsResult)
 2883                    EmitLoadLocalVariable(il, resultVarIndex);
 2884
 2885                return true;
 2886            }
 2887
 2888            public static bool TryEmitParameter(ParameterExpression paramExpr,
 2889#if LIGHT_EXPRESSION
 2890                IParameterProvider paramExprs,
 2891#else
 2892                IReadOnlyList<PE> paramExprs,
 2893#endif
 2894                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent, int byRefIndex = -1)
 2895            {
 2896                var paramExprCount = paramExprs.GetCount();
 2897                var paramType = paramExpr.Type;
 2898                var isValueType = paramType.IsValueType;
 2899                var isParamOrVarByRef = paramExpr.IsByRef && !paramType.IsNullable(); // for the nullable part check the
 2900                var isPassedRef = byRefIndex != -1;
 2901
 2902                // Parameter may represent a variable, so first look if this is the case,
 2903                // and the variable is defined in the current block
 2904                var varIndex = closure.GetDefinedLocalVarOrDefault(paramExpr);
 2905                if (varIndex != -1)
 2906                {
 2907                    // todo: @perf analyze if the variable is actually may be mutated in the nested lambda by being assi
 2908                    // Check if the variable is passed to the nested closure (#437), so it should be loaded from the nes
 2909                    var nestedLambdasCount = closure.NestedLambdas.Count;
 2910                    if (nestedLambdasCount != 0)
 2911                    {
 2912                        var nestedLambdas = closure.NestedLambdas.Items;
 2913                        for (var nestedLambdaIndex = 0; nestedLambdaIndex < nestedLambdasCount; ++nestedLambdaIndex)
 2914                        {
 2915                            var lambdaInfo = nestedLambdas[nestedLambdaIndex];
 2916                            var nonPassedParamCount = lambdaInfo.NonPassedParameters.Count;
 2917                            if (nonPassedParamCount != 0)
 2918                            {
 2919                                var varIndexInNonPassedParams = lambdaInfo.NonPassedParameters.TryGetIndex(paramExpr, de
 2920                                if (varIndexInNonPassedParams != -1 &&
 2921                                    (lambdaInfo.NonPassedParamMutatedIndexBits & (1UL << varIndexInNonPassedParams)) != 
 2922                                {
 2923                                    // Load the nested lambda item from the closure constants and nested lambdas array
 2924                                    var closureArrayItemIndex = closure.Constants.Count + nestedLambdaIndex;
 2925                                    EmitLoadClosureArrayItem(il, closureArrayItemIndex);
 2926
 2927                                    // Check if the NonPassedArray field is being set (not null),
 2928                                    // otherwise the nested lambda is not yet emitted, and it is not expected for the va
 2929                                    il.Demit(OpCodes.Ldfld, NestedLambdaForNonPassedParams.NonPassedParamsField);
 2930
 2931                                    // Load the variable from the NonPassedParams array
 2932                                    EmitLoadConstantInt(il, varIndexInNonPassedParams);
 2933                                    il.Demit(OpCodes.Ldelem_Ref);
 2934                                    il.TryEmitUnboxOf(paramType);
 2935                                    return true;
 2936                                }
 2937                            }
 2938                        }
 2939                    }
 2940
 2941                    var valueTypeMemberButNotIndexAccess = isValueType &
 2942                        // means the parameter is the instance for the called method or the instance for the member acce
 2943                        (parent & (ParentFlags.MemberAccess | ParentFlags.InstanceAccess)) != 0 &
 2944                        (
 2945                            // but the variable is not used as an index for the method call or the member access
 2946                            // `a[i].Foo()` -> false, see #281
 2947                            // `a[i].Bar`   -> false, see #265
 2948                            // `a[i]`       -> true,  see #413
 2949                            (parent & ParentFlags.IndexAccess) == 0 |
 2950                            (parent & (ParentFlags.Call | ParentFlags.MemberAccess)) == 0
 2951                        );
 2952
 2953                    closure.LastEmitIsAddress = !isParamOrVarByRef & (isPassedRef | valueTypeMemberButNotIndexAccess);
 2954
 2955                    if (closure.LastEmitIsAddress)
 2956                        EmitLoadLocalVariableAddress(il, varIndex);
 2957                    else if (!isParamOrVarByRef)
 2958                        EmitLoadLocalVariable(il, varIndex);
 2959                    else
 2960                    {
 2961                        if (isParamOrVarByRef & isValueType &
 2962                            (parent & ParentFlags.BlockResult) != 0 &
 2963                            (parent & (ParentFlags.MemberAccess | ParentFlags.Call | ParentFlags.InstanceAccess | Parent
 2964                        {
 2965                            EmitLoadIndirectlyByRef(il, paramType);
 2966                            return true;
 2967                        }
 2968
 2969                        var byAddress = isParamOrVarByRef & isPassedRef & isValueType;
 2970                        if (byAddress)
 2971                            EmitStoreAndLoadLocalVariableAddress(il, varIndex);
 2972                        else if ((parent & ParentFlags.InstanceCall) == ParentFlags.InstanceCall)
 2973                            EmitLoadLocalVariable(il, varIndex);
 2974                        else
 2975                            EmitStoreAndLoadLocalVariable(il, varIndex);
 2976
 2977                        // Assume that the var is the last on the stack and just duplicating it, see #346 `Get_array_ele
 2978                        // Do only when accessing the variable directly, and not the member and the array element by ind
 2979                        if (byAddress)
 2980                            il.Demit(OpCodes.Dup);
 2981                        else if ((parent & ParentFlags.InstanceAccess) == 0)
 2982                            EmitLoadLocalVariable(il, varIndex);
 2983
 2984                        if (isValueType)
 2985                        {
 2986                            if ((parent & (ParentFlags.Arithmetic | ParentFlags.AssignmentRightValue)) != 0 &
 2987                                (parent & (ParentFlags.MemberAccess | ParentFlags.InstanceAccess)) == 0)
 2988                                EmitLoadIndirectlyByRef(il, paramType);
 2989                        }
 2990                        else
 2991                        {
 2992                            if ((parent & (ParentFlags.Coalesce | ParentFlags.MemberAccess | ParentFlags.IndexAccess | P
 2993                                il.Demit(OpCodes.Ldind_Ref);
 2994                        }
 2995                    }
 2996                    return true;
 2997                }
 2998
 2999                // If not variable then look if the parameter is passed to the current lambda
 3000                var paramIndex = paramExprCount - 1;
 3001                while (paramIndex != -1 && !ReferenceEquals(paramExprs.GetParameter(paramIndex), paramExpr)) --paramInde
 3002                if (paramIndex != -1)
 3003                {
 3004                    if ((closure.Status & ClosureStatus.ShouldBeStaticMethod) == 0)
 3005                        ++paramIndex; // shift parameter index by one, because the first one will be closure
 3006
 3007                    //  means the parameter is the instance for what method is called or the instance for the member acc
 3008                    var valueTypeMemberButNotIndexAccess = isValueType &
 3009                        // means the parameter is the instance for what method is called or the instance for the member 
 3010                        (parent & (ParentFlags.MemberAccess | ParentFlags.InstanceAccess)) != 0 &
 3011                        // see #352 for the arithmetic
 3012                        (parent & ParentFlags.Arithmetic) == 0 &
 3013                        (
 3014                            // but the variable is not used as an index for the method call or the member access
 3015                            // `a[i].Foo()` -> false, see #281
 3016                            // `a[i].Bar`   -> false, see #265
 3017                            // `a[i]`       -> true,  see #413
 3018                            (parent & ParentFlags.IndexAccess) == 0 |
 3019                            (parent & (ParentFlags.Call | ParentFlags.MemberAccess)) == 0
 3020                        );
 3021
 3022                    closure.LastEmitIsAddress = !isParamOrVarByRef & (isPassedRef | valueTypeMemberButNotIndexAccess);
 3023
 3024                    if (closure.LastEmitIsAddress)
 3025                        EmitLoadArgAddress(il, paramIndex);
 3026                    else
 3027                        EmitLoadArg(il, paramIndex);
 3028
 3029                    // todo: @simplify as it is complex overall and EmitLoadIndirectlyByRef does the Ldind_Ref too
 3030                    if (isParamOrVarByRef)
 3031                    {
 3032                        // todo: @wip requires a cleanup
 3033                        if (isValueType)
 3034                        {
 3035                            // #248 - skip the cases with `ref param.Field` were we are actually want to load the `Field
 3036                            // this means the parameter is the argument to the method call and not the instance in the m
 3037                            if (!isPassedRef & (
 3038                                ((parent & ParentFlags.Call) != 0 & (parent & ParentFlags.InstanceAccess) == 0) |
 3039                                ((parent & ParentFlags.LambdaCall) != 0 & (parent & ParentFlags.ReturnByRef) == 0)
 3040                                ) ||
 3041                                (parent & (ParentFlags.Arithmetic | ParentFlags.AssignmentRightValue)) != 0 &
 3042                                (parent & (ParentFlags.MemberAccess | ParentFlags.InstanceAccess | ParentFlags.Assignmen
 3043                                EmitLoadIndirectlyByRef(il, paramType);
 3044                        }
 3045                        else
 3046                        {
 3047                            if (!isPassedRef & (
 3048                                (parent & (ParentFlags.Call | ParentFlags.LambdaCall)) != 0) ||
 3049                                (parent & (ParentFlags.Coalesce | ParentFlags.MemberAccess | ParentFlags.IndexAccess | P
 3050                                il.Demit(OpCodes.Ldind_Ref);
 3051                        }
 3052                    }
 3053                    return true;
 3054                }
 3055
 3056                if (isParamOrVarByRef)
 3057                {
 3058                    EmitLoadLocalVariableAddress(il, byRefIndex); // todo: @bug? `closure.LastEmitIsAddress = true;` sho
 3059                    return true;
 3060                }
 3061
 3062                // the only possibility that we are here is because we are in the nested lambda,
 3063                // and it uses the parameter or variable from the outer lambda
 3064                var nonPassedParamIndex = closure.NonPassedParameters.TryGetIndex(paramExpr, default(RefEq<ParameterExpr
 3065                if (nonPassedParamIndex == -1)
 3066                    return false;
 3067
 3068                // Load non-passed argument from Closure - closure object is always a first argument
 3069                il.Demit(OpCodes.Ldarg_0);
 3070                il.Demit(OpCodes.Ldfld, ArrayClosureWithNonPassedParamsField);
 3071                EmitLoadConstantInt(il, nonPassedParamIndex);
 3072                il.Demit(OpCodes.Ldelem_Ref);
 3073                return il.TryEmitUnboxOf(paramType);
 3074            }
 3075
 3076#if LIGHT_EXPRESSION
 3077            public static bool TryEmitNonByRefNonValueTypeParameter(ParameterExpression paramExpr, IParameterProvider pa
 3078            {
 3079                var paramExprCount = paramExprs.ParameterCount;
 3080#else
 3081            public static bool TryEmitNonByRefNonValueTypeParameter(ParameterExpression paramExpr, IReadOnlyList<PE> par
 3082            {
 3083                var paramExprCount = paramExprs.Count;
 3084#endif
 3085                // if parameter is passed through, then just load it on stack
 3086                var paramType = paramExpr.Type;
 3087                var paramIndex = paramExprCount - 1;
 3088                while (paramIndex != -1 && !ReferenceEquals(paramExprs.GetParameter(paramIndex), paramExpr))
 3089                    --paramIndex;
 3090                if (paramIndex != -1)
 3091                {
 3092                    if ((closure.Status & ClosureStatus.ShouldBeStaticMethod) == 0)
 3093                        ++paramIndex; // shift parameter index by one, because the first one will be closure
 3094                    if (closure.LastEmitIsAddress)
 3095                        EmitLoadArgAddress(il, paramIndex);
 3096                    else
 3097                        EmitLoadArg(il, paramIndex);
 3098                    return true;
 3099                }
 3100
 3101                // the only possibility that we are here is because we are in the nested lambda,
 3102                // and it uses the parameter or variable from the outer lambda
 3103                var nonPassedParamIndex = closure.NonPassedParameters.TryGetIndex(paramExpr, default(RefEq<ParameterExpr
 3104                if (nonPassedParamIndex == -1)
 3105                    return false;
 3106
 3107                // Load non-passed argument from Closure - closure object is always a first argument
 3108                il.Demit(OpCodes.Ldarg_0);
 3109                il.Demit(OpCodes.Ldfld, ArrayClosureWithNonPassedParamsField);
 3110                EmitLoadConstantInt(il, nonPassedParamIndex);
 3111                il.Demit(OpCodes.Ldelem_Ref);
 3112                return true;
 3113            }
 3114
 3115            private static bool TryEmitSimpleUnaryExpression(UnaryExpression expr, ExpressionType nodeType,
 3116#if LIGHT_EXPRESSION
 3117                IParameterProvider paramExprs,
 3118#else
 3119                IReadOnlyList<PE> paramExprs,
 3120#endif
 3121                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 3122            {
 3123                var exprType = expr.Type;
 3124
 3125                if (!TryEmit(expr.Operand, paramExprs, il, ref closure, setup, parent))
 3126                    return false;
 3127
 3128                if (nodeType == ExpressionType.TypeAs)
 3129                {
 3130                    il.TryEmitBoxOf(expr.Operand.Type);
 3131                    il.Demit(OpCodes.Isinst, exprType);
 3132                    if (exprType.IsValueType)
 3133                        il.Demit(OpCodes.Unbox_Any, exprType);
 3134                }
 3135                else if (nodeType == ExpressionType.IsFalse)
 3136                {
 3137                    var falseLabel = il.DefineLabel();
 3138                    var continueLabel = il.DefineLabel();
 3139                    il.Demit(OpCodes.Brfalse, falseLabel);
 3140                    il.Demit(OpCodes.Ldc_I4_0);
 3141                    il.Demit(OpCodes.Br, continueLabel);
 3142                    il.DmarkLabel(falseLabel);
 3143                    il.Demit(OpCodes.Ldc_I4_1);
 3144                    il.DmarkLabel(continueLabel);
 3145                }
 3146                else if (nodeType == ExpressionType.Increment)
 3147                {
 3148                    if (exprType.IsPrimitive)
 3149                    {
 3150                        if (!TryEmitNumberOne(il, exprType))
 3151                            return false;
 3152                        il.Demit(OpCodes.Add);
 3153                    }
 3154                    else if (!EmitMethodCallCheckForNull(il, exprType.GetMethod("op_Increment")))
 3155                        return false;
 3156                }
 3157                else if (nodeType == ExpressionType.Decrement)
 3158                {
 3159                    if (exprType.IsPrimitive)
 3160                    {
 3161                        if (!TryEmitNumberOne(il, exprType))
 3162                            return false;
 3163                        il.Demit(OpCodes.Sub);
 3164                    }
 3165                    else if (!EmitMethodCallCheckForNull(il, exprType.GetMethod("op_Decrement")))
 3166                        return false;
 3167                }
 3168                else if (nodeType == ExpressionType.Negate | nodeType == ExpressionType.NegateChecked)
 3169                {
 3170                    if (exprType.IsPrimitive)
 3171                        il.Demit(OpCodes.Neg);
 3172                    else if (!EmitMethodCallCheckForNull(il, exprType.GetMethod("op_UnaryNegation")))
 3173                        return false;
 3174                }
 3175                else if (nodeType == ExpressionType.OnesComplement)
 3176                    il.Demit(OpCodes.Not);
 3177                else if (nodeType == ExpressionType.Unbox)
 3178                    il.Demit(OpCodes.Unbox_Any, exprType);
 3179                // else if (nodeType == ExpressionType.IsTrue) { }
 3180                // else if (nodeType == ExpressionType.UnaryPlus) { }
 3181
 3182                return il.EmitPopIfIgnoreResult(parent);
 3183            }
 3184
 3185            private static bool TryEmitTypeIsOrEqual(TypeBinaryExpression expr,
 3186#if LIGHT_EXPRESSION
 3187                IParameterProvider paramExprs,
 3188#else
 3189                IReadOnlyList<PE> paramExprs,
 3190#endif
 3191                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 3192            {
 3193                if (!TryEmit(expr.Expression, paramExprs, il, ref closure, setup, parent))
 3194                    return false;
 3195                if ((parent & ParentFlags.IgnoreResult) != 0)
 3196                    return true;
 3197                if (expr.NodeType == ExpressionType.TypeIs)
 3198                {
 3199                    il.Demit(OpCodes.Isinst, expr.TypeOperand);
 3200                    il.Demit(OpCodes.Ldnull);
 3201                    il.Demit(OpCodes.Cgt_Un);
 3202                    return true;
 3203                }
 3204                if ((setup & CompilerFlags.ThrowOnNotSupportedExpression) != 0)
 3205                    throw new NotSupportedExpressionException(Result.NotSupported_TypeEqual);
 3206                return false;
 3207            }
 3208
 3209            private static bool TryEmitNot(UnaryExpression expr,
 3210#if LIGHT_EXPRESSION
 3211                IParameterProvider paramExprs,
 3212#else
 3213                IReadOnlyList<PE> paramExprs,
 3214#endif
 3215                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 3216            {
 3217                var op = expr.Operand;
 3218                if (op.NodeType == ExpressionType.Equal)
 3219                    return TryEmitComparison(((BinaryExpression)op).Left, ((BinaryExpression)op).Right,
 3220                        expr.Type, ExpressionType.NotEqual, paramExprs, il, ref closure, setup, parent);
 3221
 3222                if (!TryEmit(op, paramExprs, il, ref closure, setup, parent))
 3223                    return false;
 3224
 3225                if ((parent & ParentFlags.IgnoreResult) != 0)
 3226                    il.Demit(OpCodes.Pop);
 3227                else if (expr.Type == typeof(bool))
 3228                    EmitEqualToZeroOrNull(il);
 3229                else
 3230                    il.Demit(OpCodes.Not);
 3231                return true;
 3232            }
 3233
 3234            private static bool TryEmitConvert(UnaryExpression expr,
 3235#if LIGHT_EXPRESSION
 3236                IParameterProvider paramExprs,
 3237#else
 3238                IReadOnlyList<PE> paramExprs,
 3239#endif
 3240                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 3241            {
 3242                var opExpr = expr.Operand;
 3243                var sourceType = opExpr.Type;
 3244                var targetType = expr.Type;
 3245                var underlyingNullableSourceType = sourceType.GetUnderlyingNullableTypeOrNull();
 3246                var underlyingNullableTargetType = targetType.GetUnderlyingNullableTypeOrNull();
 3247
 3248                var convertMethod = expr.Method;
 3249                if (convertMethod == null)
 3250                {
 3251                    // Try fast the special cases which does not require searching for the conversion operators in princ
 3252                    if (parent.IgnoresResult() && (sourceType == targetType || targetType.IsAssignableFrom(sourceType)))
 3253                        return TryEmit(opExpr, paramExprs, il, ref closure, setup, parent & ~ParentFlags.InstanceAccess)
 3254
 3255                    // Emit the operand before going to the fast checks below
 3256                    if (!TryEmit(opExpr, paramExprs, il, ref closure, setup, parent & ~ParentFlags.IgnoreResult & ~Paren
 3257                        return false;
 3258
 3259                    if (sourceType == targetType)
 3260                        return il.EmitPopIfIgnoreResult(parent);
 3261
 3262                    if (targetType == underlyingNullableSourceType)
 3263                    {
 3264                        if (!closure.LastEmitIsAddress)
 3265                            EmitStoreAndLoadLocalVariableAddress(il, sourceType);
 3266                        EmitMethodCall(il, sourceType.GetNullableValueGetterMethod());
 3267                        return il.EmitPopIfIgnoreResult(parent);
 3268                    }
 3269
 3270                    if (sourceType == underlyingNullableTargetType)
 3271                    {
 3272                        il.Demit(OpCodes.Newobj, targetType.GetNullableConstructor());
 3273                        return il.EmitPopIfIgnoreResult(parent);
 3274                    }
 3275
 3276                    if (targetType == typeof(object) && sourceType.IsValueType)
 3277                    {
 3278                        il.Demit(OpCodes.Box, sourceType);
 3279                        return il.EmitPopIfIgnoreResult(parent);
 3280                    }
 3281
 3282                    if (sourceType == typeof(object) && targetType.IsValueType ||
 3283                        sourceType == typeof(Enum) && targetType.IsEnum // a special case, see the AutoMapper test `Stri
 3284                    )
 3285                    {
 3286                        il.Demit(OpCodes.Unbox_Any, targetType);
 3287                        return il.EmitPopIfIgnoreResult(parent);
 3288                    }
 3289
 3290                    // At least just check the assignability of the source to the target type,
 3291                    // check only after the checks above for the ValueType or object Type,
 3292                    // because their require additional boxing/unboxing operations
 3293                    if (targetType.IsAssignableFrom(sourceType))
 3294                    {
 3295                        if (sourceType.IsValueType && !targetType.IsValueType)
 3296                            il.Demit(OpCodes.Box, sourceType);
 3297                        il.Demit(OpCodes.Castclass, targetType);
 3298                        return il.EmitPopIfIgnoreResult(parent);
 3299                    }
 3300                }
 3301
 3302                // Check implicit / explicit conversion operators on source and then on the target type,
 3303                // check their underlying nullable types, because Nullable does not contain conversion ops,
 3304                // also check inside that it is not primitive type, nor string or enum because those do no contain the c
 3305                // see #73, #451 for examples
 3306                Type methodReturnType = null;
 3307                Type methodParamType = null;
 3308                if (convertMethod != null)
 3309                {
 3310                    methodReturnType = convertMethod.ReturnType;
 3311
 3312                    var mParams = convertMethod.GetParameters();
 3313                    Debug.Assert(mParams.Length == 1, $"Expected for the conversion operator to have a single param, but
 3314                    methodParamType = mParams[0].ParameterType;
 3315
 3316                    // todo: @wip check if we need to add the ParentFlags.Call here?
 3317                    if (!TryEmit(opExpr, paramExprs, il, ref closure, setup, parent & ~ParentFlags.IgnoreResult & ~Paren
 3318                        return false;
 3319                }
 3320                else
 3321                {
 3322                    // Lookup for the conversion method first in sourceType then in the targetType
 3323                    Type underlyingOrNullableSourceType = null;
 3324                    for (var lookupCount = 0; lookupCount < 2 & convertMethod == null; ++lookupCount)
 3325                    {
 3326                        var convOwnerType = lookupCount == 0
 3327                            ? underlyingNullableSourceType ?? sourceType
 3328                            : underlyingNullableTargetType ?? targetType;
 3329
 3330                        if (convOwnerType == typeof(string) || convOwnerType.IsEnum || convOwnerType.IsPrimitive)
 3331                            continue;
 3332
 3333                        var staticMethods = convOwnerType.GetMethods(BindingFlags.Static | BindingFlags.Public);
 3334                        foreach (var m in staticMethods)
 3335                        {
 3336                            if (!m.IsSpecialName)
 3337                                continue;
 3338
 3339                            // Method return type should be convertible to target type,
 3340                            // and therefore it does not check for the method return type of Nullable<targetType>
 3341                            // because it cannot be coalesced to targetType without loss of information
 3342                            methodReturnType = m.ReturnType;
 3343                            if (methodReturnType != targetType && methodReturnType != underlyingNullableTargetType ||
 3344                                m.Name != "op_Implicit" && m.Name != "op_Explicit")
 3345                                continue;
 3346
 3347                            var operatorParams = m.GetParameters();
 3348                            Debug.Assert(operatorParams.Length == 1, $"Expected for the conversion operator to have a si
 3349
 3350                            methodParamType = operatorParams[0].ParameterType;
 3351                            if (methodParamType == sourceType)
 3352                            {
 3353                                convertMethod = m;
 3354                                break;
 3355                            }
 3356
 3357                            // This next check is only valid if the source type is the ValueType, so it can be either a 
 3358                            if (sourceType.IsValueType)
 3359                            {
 3360                                // Check for all variants of the source type which maybe either underlying nullable or n
 3361                                // Calculate it once because less work is better.
 3362                                underlyingOrNullableSourceType ??= underlyingNullableSourceType ?? sourceType.GetNullabl
 3363                                if (methodParamType == underlyingOrNullableSourceType)
 3364                                {
 3365                                    convertMethod = m;
 3366                                    break;
 3367                                }
 3368                            }
 3369                        }
 3370                    }
 3371                }
 3372
 3373                if (convertMethod != null)
 3374                {
 3375                    Debug.Assert(methodParamType != null & methodReturnType != null,
 3376                        "Expecting that actual source and return type are set for the found conversion operator method")
 3377
 3378                    // For the both nullable source and target types,
 3379                    // first check the source value for null and return null without calling the conversion method, othe
 3380                    if (methodParamType == underlyingNullableSourceType & underlyingNullableTargetType != null)
 3381                    {
 3382                        var sourceVarIndex = EmitStoreAndLoadLocalVariableAddress(il, sourceType);
 3383                        EmitMethodCall(il, sourceType.GetNullableHasValueGetterMethod());
 3384
 3385                        var labelSourceHasValue = il.DefineLabel();
 3386                        il.Demit(OpCodes.Brtrue_S, labelSourceHasValue); // Jump to this label when the source has a val
 3387
 3388                        // Otherwise, emit and load the default nullable target without value, e.g. `default(Nullable<TT
 3389                        // then... the conversion is completed, so jumping to the done label
 3390                        EmitLoadLocalVariable(il, InitValueTypeVariable(il, targetType));
 3391                        var labelConversionDone = il.DefineLabel();
 3392                        il.Demit(OpCodes.Br_S, labelConversionDone);
 3393
 3394                        // If the nullable source has the value, do the conversion
 3395                        il.DmarkLabel(labelSourceHasValue);
 3396                        EmitLoadLocalVariableAddress(il, sourceVarIndex);
 3397                        il.Demit(OpCodes.Ldfld, sourceType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod());
 3398
 3399                        EmitMethodCallOrVirtualCall(il, convertMethod);
 3400
 3401                        // Wrap the conversion result into the target type only if the conversion method return the unde
 3402                        // otherwise we done
 3403                        if (methodReturnType == underlyingNullableTargetType)
 3404                            il.Demit(OpCodes.Newobj, targetType.GetNullableConstructor());
 3405
 3406                        il.DmarkLabel(labelConversionDone);
 3407                        return il.EmitPopIfIgnoreResult(parent);
 3408                    }
 3409
 3410                    if (methodParamType == underlyingNullableSourceType)
 3411                    {
 3412                        EmitStoreAndLoadLocalVariableAddress(il, sourceType);
 3413                        EmitMethodCall(il, sourceType.GetNullableValueGetterMethod());
 3414                    }
 3415                    else if (methodParamType != sourceType) // This is an unlikely case of Target(Source? source)
 3416                    {
 3417                        Debug.Assert(methodParamType.GetUnderlyingNullableTypeOrNull() == sourceType, "Expecting that th
 3418                        il.Demit(OpCodes.Newobj, methodParamType.GetNullableConstructor());
 3419                    }
 3420
 3421                    EmitMethodCallOrVirtualCall(il, convertMethod);
 3422
 3423                    if (methodReturnType == underlyingNullableTargetType)
 3424                        il.Demit(OpCodes.Newobj, targetType.GetNullableConstructor());
 3425
 3426                    return il.EmitPopIfIgnoreResult(parent);
 3427                }
 3428
 3429                if (underlyingNullableSourceType != null & underlyingNullableTargetType != null)
 3430                {
 3431                    var sourceVarIndex = EmitStoreAndLoadLocalVariableAddress(il, sourceType);
 3432                    EmitMethodCall(il, sourceType.GetNullableHasValueGetterMethod());
 3433
 3434                    var labelSourceHasValue = il.DefineLabel();
 3435                    il.Demit(OpCodes.Brtrue_S, labelSourceHasValue); // Jump here when the source has a value
 3436
 3437                    // Otherwise, emit and load the default nullable target without value, e.g. `default(Nullable<TTarge
 3438                    // and... the conversion is completed, so jumping to the done label
 3439                    EmitLoadLocalVariable(il, InitValueTypeVariable(il, targetType));
 3440                    var labelConversionDone = il.DefineLabel();
 3441                    il.Demit(OpCodes.Br_S, labelConversionDone);
 3442
 3443                    // If the nullable source has the value, do the conversion
 3444                    il.DmarkLabel(labelSourceHasValue);
 3445                    EmitLoadLocalVariableAddress(il, sourceVarIndex);
 3446                    il.Demit(OpCodes.Ldfld, sourceType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod());
 3447
 3448                    if (!TryEmitPrimitiveValueConvert(underlyingNullableSourceType, underlyingNullableTargetType, il, ex
 3449                        return false;
 3450
 3451                    il.Demit(OpCodes.Newobj, targetType.GetNullableConstructor());
 3452
 3453                    // We done here.
 3454                    il.DmarkLabel(labelConversionDone);
 3455                    return il.EmitPopIfIgnoreResult(parent);
 3456                }
 3457
 3458                if (underlyingNullableTargetType != null) // sourceType is NOT nullable here (checked above)
 3459                {
 3460                    if (!underlyingNullableTargetType.IsEnum &&
 3461                        !TryEmitPrimitiveValueConvert(sourceType, underlyingNullableTargetType, il, isChecked: false))
 3462                        return false;
 3463                    il.Demit(OpCodes.Newobj, targetType.GetNullableConstructor());
 3464                }
 3465                else // targetType is NOT nullable here (checked above)
 3466                {
 3467                    if (targetType.IsEnum)
 3468                    {
 3469                        targetType = Enum.GetUnderlyingType(targetType);
 3470                        if (targetType == sourceType)
 3471                            return il.EmitPopIfIgnoreResult(parent);
 3472                    }
 3473
 3474                    // fixes #159
 3475                    if (underlyingNullableSourceType != null)
 3476                    {
 3477                        EmitStoreAndLoadLocalVariableAddress(il, sourceType);
 3478                        EmitMethodCall(il, sourceType.GetNullableValueGetterMethod());
 3479                    }
 3480
 3481                    // Cast as the last resort and let's it fail if unlucky
 3482                    if (!TryEmitPrimitiveValueConvert(underlyingNullableSourceType ?? sourceType, targetType, il, expr.N
 3483                    {
 3484                        il.TryEmitBoxOf(sourceType);
 3485                        il.Demit(OpCodes.Castclass, targetType);
 3486                    }
 3487                }
 3488
 3489                return il.EmitPopIfIgnoreResult(parent);
 3490            }
 3491
 3492            private static bool TryEmitPrimitiveValueConvert(Type sourceType, Type targetType, ILGenerator il, bool isCh
 3493            {
 3494                switch (Type.GetTypeCode(targetType))
 3495                {
 3496                    case TypeCode.SByte:
 3497                        il.Demit(isChecked ? OpCodes.Conv_Ovf_I1 : OpCodes.Conv_I1);
 3498                        break;
 3499                    case TypeCode.Byte:
 3500                        il.Demit(isChecked ? OpCodes.Conv_Ovf_U1 : OpCodes.Conv_U1);
 3501                        break;
 3502                    case TypeCode.Int16:
 3503                        il.Demit(isChecked ? OpCodes.Conv_Ovf_I2 : OpCodes.Conv_I2);
 3504                        break;
 3505                    case TypeCode.Int32:
 3506                        il.Demit(isChecked ? OpCodes.Conv_Ovf_I4 : OpCodes.Conv_I4);
 3507                        break;
 3508                    case TypeCode.Int64:
 3509                        il.Demit(isChecked ? OpCodes.Conv_Ovf_I8 : OpCodes.Conv_I8);
 3510                        break;
 3511                    case TypeCode.Double:
 3512                        il.Demit(OpCodes.Conv_R8);
 3513                        break;
 3514                    case TypeCode.Single:
 3515                        if (sourceType == typeof(uint))
 3516                            il.Demit(OpCodes.Conv_R_Un);
 3517                        il.Demit(OpCodes.Conv_R4);
 3518                        break;
 3519                    case TypeCode.UInt16:
 3520                    case TypeCode.Char:
 3521                        il.Demit(isChecked ? OpCodes.Conv_Ovf_U2 : OpCodes.Conv_U2);
 3522                        break;
 3523                    case TypeCode.UInt32:
 3524                        il.Demit(isChecked ? OpCodes.Conv_Ovf_U4 : OpCodes.Conv_U4);
 3525                        break;
 3526                    case TypeCode.UInt64:
 3527                        il.Demit(isChecked ? OpCodes.Conv_Ovf_U8 : OpCodes.Conv_U8); // should we consider if sourceType
 3528                        break;
 3529                    default:
 3530                        // todo: @feature for net7+ add Half, Int128, UInt128
 3531                        return false;
 3532                }
 3533                return true;
 3534            }
 3535
 3536            public static bool TryEmitConstant(ConstantExpression expr, Type exprType, ILGenerator il, ref ClosureInfo c
 3537            {
 3538                var ok = false;
 3539#if LIGHT_EXPRESSION
 3540                if (expr == NullConstant)
 3541                {
 3542                    il.Demit(OpCodes.Ldnull);
 3543                    ok = true;
 3544                }
 3545                else if (expr == FalseConstant | expr == ZeroConstant)
 3546                {
 3547                    il.Demit(OpCodes.Ldc_I4_0);
 3548                    ok = true;
 3549                }
 3550                else if (expr == TrueConstant | expr == OneConstant)
 3551                {
 3552                    il.Demit(OpCodes.Ldc_I4_1);
 3553                    ok = true;
 3554                }
 3555                else if (expr is IntConstantExpression n)
 3556                {
 3557                    EmitLoadConstantInt(il, (int)n.Value);
 3558                    ok = true;
 3559                }
 3560#endif
 3561                if (!ok)
 3562                {
 3563                    var constValue = expr.Value;
 3564                    if (constValue != null)
 3565                        ok = TryEmitConstant(closure.ContainsConstantsOrNestedLambdas(), exprType, constValue.GetType(),
 3566                    else if (exprType.IsValueType)
 3567                        // null for a value type and yep, this is a proper way to emit the Nullable null
 3568                        ok = EmitLoadLocalVariable(il, InitValueTypeVariable(il, exprType));
 3569                    else
 3570                    {
 3571                        il.Demit(OpCodes.Ldnull);
 3572                        ok = true;
 3573                    }
 3574                }
 3575
 3576                if (ok & byRefIndex != -1)
 3577                    EmitStoreAndLoadLocalVariableAddress(il, exprType);
 3578                return ok;
 3579            }
 3580
 3581            [MethodImpl((MethodImplOptions)256)]
 3582            public static bool TryEmitNotNullConstant(bool considerClosure, object constValue, ILGenerator il, ref Closu
 3583            {
 3584                Debug.Assert(constValue != null, "Expecting that the constant value is not null here");
 3585                var constType = constValue.GetType();
 3586                var ok = TryEmitConstant(considerClosure, null, constType, constValue, il, ref closure, byRefIndex);
 3587                if (ok & byRefIndex != -1)
 3588                    EmitStoreAndLoadLocalVariableAddress(il, constType);
 3589                return ok;
 3590            }
 3591
 3592            public static bool TryEmitConstant(bool considerClosure, Type exprType, Type constType, object constValue, I
 3593                int byRefIndex = -1, FieldInfo refField = null)
 3594            {
 3595                if (exprType == null)
 3596                    exprType = constType;
 3597#if LIGHT_EXPRESSION
 3598                if (considerClosure && (refField != null || IsClosureBoundConstant(constValue, constType)))
 3599#else
 3600                if (considerClosure && IsClosureBoundConstant(constValue, constType))
 3601#endif
 3602                {
 3603                    var constIndex = closure.Constants.TryGetIndex(constValue, default(RefEq<object>));
 3604                    if (constIndex == -1)
 3605                        return false; // todo: @check should we throw an exception instead?
 3606
 3607                    var varIndex = closure.ConstantUsageThenVarIndex[constIndex] - 1;
 3608                    if (varIndex > 0)
 3609                        EmitLoadLocalVariable(il, varIndex);
 3610                    else
 3611                    {
 3612                        EmitLoadClosureArrayItem(il, constIndex);
 3613#if LIGHT_EXPRESSION
 3614                        // Handle the loading of the ref field if the constant usage is only once,
 3615                        // for the multiple usages the field was loaded and saved into variable in `EmitLoadConstantsAnd
 3616                        if (refField != null)
 3617                        {
 3618                            il.Demit(OpCodes.Ldfld, refField);
 3619                            if (refField.FieldType != typeof(object))
 3620                                return true; // for typed constant we done,
 3621                            // but the object ref field requires the normal constant treatment with unboxing of the Valu
 3622                            exprType = constType = ((ConstantExpression)constValue).Value.GetType();
 3623                        }
 3624#endif
 3625                        if (constType.IsValueType)
 3626                            il.Demit(OpCodes.Unbox_Any, constType);
 3627#if NETFRAMEWORK
 3628                        else
 3629                            // The cast is probably required only for the Full CLR,
 3630                            // e.g. `Test_283_Case6_MappingSchemaTests_CultureInfo_VerificationException`.
 3631                            // .NET Core does not seem to care about verifiability and it's faster without the explicit 
 3632                            il.Demit(OpCodes.Castclass, constType);
 3633#endif
 3634                    }
 3635                }
 3636                else
 3637                {
 3638                    if (constValue is string s)
 3639                    {
 3640                        il.Demit(s, OpCodes.Ldstr);
 3641                        return true;
 3642                    }
 3643                    if (constValue is Type t)
 3644                    {
 3645                        il.Demit(OpCodes.Ldtoken, t);
 3646                        return EmitMethodCall(il, GetTypeFromHandleMethod);
 3647                    }
 3648                    if (!TryEmitPrimitiveOrEnumOrDecimalConstant(il, constValue, constType))
 3649                        return false;
 3650                }
 3651
 3652                if (exprType != constType && constType.IsValueType)
 3653                {
 3654                    if (exprType.IsNullable())
 3655                        il.Demit(OpCodes.Newobj, exprType.GetNullableConstructor());
 3656                    else if (exprType == typeof(object))
 3657                        il.Demit(OpCodes.Box, constType); // using normal type for Enum instead of underlying type
 3658                }
 3659                return true;
 3660            }
 3661
 3662            /// <summary>Emit the IL for the value of the primitive type.</summary>
 3663            public static bool TryEmitPrimitiveOrEnumOrDecimalConstant(ILGenerator il, object constValue, Type constType
 3664            {
 3665                if (constType.IsEnum)
 3666                    constType = Enum.GetUnderlyingType(constType);
 3667
 3668                switch (Type.GetTypeCode(constType))
 3669                {
 3670                    case TypeCode.Boolean:
 3671                        il.Demit((bool)constValue ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); // todo: @perf check for Light
 3672                        break;
 3673                    case TypeCode.Char:
 3674                        EmitLoadConstantInt(il, (char)constValue);
 3675                        break;
 3676                    case TypeCode.SByte:
 3677                        EmitLoadConstantInt(il, (sbyte)constValue);
 3678                        break;
 3679                    case TypeCode.Byte:
 3680                        EmitLoadConstantInt(il, (byte)constValue);
 3681                        break;
 3682                    case TypeCode.Int16:
 3683                        EmitLoadConstantInt(il, (short)constValue);
 3684                        break;
 3685                    case TypeCode.UInt16:
 3686                        EmitLoadConstantInt(il, (ushort)constValue);
 3687                        break;
 3688                    case TypeCode.Int32:
 3689                        EmitLoadConstantInt(il, (int)constValue);
 3690                        break;
 3691                    case TypeCode.UInt32:
 3692                        unchecked
 3693                        {
 3694                            EmitLoadConstantInt(il, (int)(uint)constValue);
 3695                        }
 3696                        break;
 3697                    case TypeCode.Int64:
 3698                        il.Demit(OpCodes.Ldc_I8, (long)constValue);
 3699                        break;
 3700                    case TypeCode.UInt64:
 3701                        unchecked
 3702                        {
 3703                            il.Demit(OpCodes.Ldc_I8, (long)(ulong)constValue);
 3704                        }
 3705                        break;
 3706                    case TypeCode.Double:
 3707                        il.Demit(OpCodes.Ldc_R8, (double)constValue);
 3708                        break;
 3709                    case TypeCode.Single:
 3710                        il.Demit(OpCodes.Ldc_R4, (float)constValue);
 3711                        break;
 3712                    case TypeCode.Decimal:
 3713                        EmitDecimalConstant((decimal)constValue, il);
 3714                        break;
 3715                    // todo: @feature for net7 add Half, Int128, UInt128
 3716                    default:
 3717                        if (constType == typeof(IntPtr))
 3718                        {
 3719                            il.Demit(OpCodes.Ldc_I8, ((IntPtr)constValue).ToInt64());
 3720                            break;
 3721                        }
 3722                        else if (constType == typeof(UIntPtr))
 3723                        {
 3724                            unchecked
 3725                            {
 3726                                il.Demit(OpCodes.Ldc_I8, (long)((UIntPtr)constValue).ToUInt64());
 3727                            }
 3728                            break;
 3729                        }
 3730                        return false;
 3731                }
 3732                return true;
 3733            }
 3734
 3735            // todo: @perf optimize using Type.TypeCode
 3736            internal static bool TryEmitNumberOne(ILGenerator il, Type type)
 3737            {
 3738                if (type == typeof(int) || type == typeof(char) || type == typeof(short) ||
 3739                    type == typeof(byte) || type == typeof(ushort) || type == typeof(sbyte) ||
 3740                    type == typeof(uint))
 3741                    il.Demit(OpCodes.Ldc_I4_1);
 3742                else if (type == typeof(long) || type == typeof(ulong) ||
 3743                         type == typeof(IntPtr) || type == typeof(UIntPtr))
 3744                    il.Demit(OpCodes.Ldc_I8, (long)1);
 3745                else if (type == typeof(float))
 3746                    il.Demit(OpCodes.Ldc_R4, 1f);
 3747                else if (type == typeof(double))
 3748                    il.Demit(OpCodes.Ldc_R8, 1d);
 3749                else
 3750                    return false;
 3751                return true;
 3752            }
 3753
 3754            [MethodImpl((MethodImplOptions)256)]
 3755            private static void EmitLoadClosureArrayItem(ILGenerator il, int i)
 3756            {
 3757                il.Demit(OpCodes.Ldloc_0);// SHOULD BE always at 0 location; load array field variable on the stack
 3758                EmitLoadConstantInt(il, i);
 3759                il.Demit(OpCodes.Ldelem_Ref);
 3760            }
 3761
 3762            internal static void EmitLoadConstantsAndNestedLambdasIntoVars(ILGenerator il, ref ClosureInfo closure)
 3763            {
 3764                // todo: @perf load the field to `var` only if the constants are more than 1
 3765                // Load constants array field from Closure and store it into the variable
 3766                il.Demit(OpCodes.Ldarg_0);
 3767                il.Demit(OpCodes.Ldfld, ArrayClosureArrayField);
 3768                EmitStoreLocalVariable(il, il.GetNextLocalVarIndex(typeof(object[]))); // always does Stloc_0, because i
 3769
 3770                // important that the constant will contain the nested lambdas as well in the same array after the actua
 3771                // so the Count indicates where the constants end
 3772                var constItems = closure.Constants.Items;
 3773                var constCount = closure.Constants.Count;
 3774
 3775                short varIndex;
 3776                for (var i = 0; i < constCount; i++)
 3777                {
 3778                    ref var constUsage = ref closure.ConstantUsageThenVarIndex.GetSurePresentItemRef(i);
 3779                    if (constUsage > 1) // todo: @perf should we proceed to do this or simplify and remove the usages fo
 3780                    {
 3781                        EmitLoadClosureArrayItem(il, i);
 3782                        var constValue = constItems[i];
 3783                        var constType = constValue.GetType();
 3784                        if (constType.IsValueType)
 3785                            il.Demit(OpCodes.Unbox_Any, constType);
 3786
 3787                        varIndex = (short)il.GetNextLocalVarIndex(constType);
 3788                        constUsage = (short)(varIndex + 1); // to distinguish from the default 1
 3789                        EmitStoreLocalVariable(il, varIndex);
 3790                    }
 3791                }
 3792
 3793                var nestedLambdasCount = closure.NestedLambdas.Count;
 3794                if (nestedLambdasCount != 0)
 3795                {
 3796                    var nestedLambdas = closure.NestedLambdas.Items;
 3797                    for (var i = 0; i < nestedLambdasCount; i++)
 3798                    {
 3799                        var lambdaInfo = nestedLambdas[i];
 3800                        EmitLoadClosureArrayItem(il, constCount + i);
 3801                        lambdaInfo.LambdaVarIndex = varIndex = (short)il.GetNextLocalVarIndex(lambdaInfo.Lambda.GetType(
 3802                        EmitStoreLocalVariable(il, varIndex);
 3803                    }
 3804                }
 3805            }
 3806
 3807            private static ConstructorInfo _decimalIntCtor, _decimalLongCtor;
 3808            private static FieldInfo _decimalZero, _decimalOne;
 3809
 3810            private static void EmitDecimalConstant(decimal value, ILGenerator il)
 3811            {
 3812                if (value == 0 | value == 1)
 3813                {
 3814                    // emit Decimal.Zero or Decimal.One instead of new Decimal(0) or new Decimal(1)
 3815                    var field = value == 0 ?
 3816                        _decimalZero ?? (_decimalZero = typeof(Decimal).GetField(nameof(Decimal.Zero))) :
 3817                        _decimalOne ?? (_decimalOne = typeof(Decimal).GetField(nameof(Decimal.One)));
 3818                    il.Demit(OpCodes.Ldsfld, field);
 3819                    return;
 3820                }
 3821
 3822                //check if decimal has decimal places, if not use shorter IL code (constructor from int or long)
 3823                if (value % 1 == 0)
 3824                {
 3825                    if (value >= int.MinValue && value <= int.MaxValue)
 3826                    {
 3827                        EmitLoadConstantInt(il, decimal.ToInt32(value));
 3828                        il.Demit(OpCodes.Newobj, _decimalIntCtor ?? (_decimalIntCtor = typeof(decimal).FindSingleParamCo
 3829                        return;
 3830                    }
 3831
 3832                    if (value >= long.MinValue && value <= long.MaxValue)
 3833                    {
 3834                        il.Demit(OpCodes.Ldc_I8, decimal.ToInt64(value));
 3835                        il.Demit(OpCodes.Newobj, _decimalLongCtor ?? (_decimalLongCtor = typeof(decimal).FindSingleParam
 3836                        return;
 3837                    }
 3838                }
 3839
 3840                if (value == decimal.MinValue)
 3841                {
 3842                    il.Demit(OpCodes.Ldsfld, typeof(decimal).GetField(nameof(decimal.MinValue)));
 3843                    return;
 3844                }
 3845
 3846                if (value == decimal.MaxValue)
 3847                {
 3848                    il.Demit(OpCodes.Ldsfld, typeof(decimal).GetField(nameof(decimal.MaxValue)));
 3849                    return;
 3850                }
 3851
 3852                var parts = decimal.GetBits(value);
 3853                var sign = (parts[3] & 0x80000000) != 0;
 3854                var scale = (byte)((parts[3] >> 16) & 0x7F);
 3855
 3856                EmitLoadConstantInt(il, parts[0]);
 3857                EmitLoadConstantInt(il, parts[1]);
 3858                EmitLoadConstantInt(il, parts[2]);
 3859
 3860                il.Demit(sign ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
 3861                EmitLoadConstantInt(il, scale);
 3862                il.Demit(OpCodes.Conv_U1);
 3863                il.Demit(OpCodes.Newobj, _decimalCtor.Value);
 3864            }
 3865
 3866            private static readonly Lazy<ConstructorInfo> _decimalCtor = new Lazy<ConstructorInfo>(() =>
 3867            {
 3868                foreach (var ctor in typeof(decimal).GetTypeInfo().DeclaredConstructors)
 3869                    if (ctor.GetParameters().Length == 5)
 3870                        return ctor;
 3871                return null;
 3872            });
 3873
 3874            [MethodImpl((MethodImplOptions)256)]
 3875            private static int InitValueTypeVariable(ILGenerator il, Type exprType, int valueVarIndex)
 3876            {
 3877                Debug.Assert(valueVarIndex != -1);
 3878                EmitLoadLocalVariableAddress(il, valueVarIndex);
 3879                il.Demit(OpCodes.Initobj, exprType);
 3880                return valueVarIndex;
 3881            }
 3882
 3883            // todo: @perf merge with EmitLoadLocalVariable
 3884            private static int InitValueTypeVariable(ILGenerator il, Type exprType) =>
 3885                InitValueTypeVariable(il, exprType, il.GetNextLocalVarIndex(exprType));
 3886
 3887#if LIGHT_EXPRESSION
 3888            private static bool EmitNewArrayBounds(NewArrayExpression expr, IParameterProvider paramExprs,
 3889                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 3890            {
 3891                var bounds = (IArgumentProvider)expr;
 3892                var boundCount = bounds.ArgumentCount;
 3893#else
 3894            private static bool EmitNewArrayBounds(NewArrayExpression expr, IReadOnlyList<PE> paramExprs,
 3895                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 3896            {
 3897                var bounds = expr.Expressions;
 3898                var boundCount = bounds.Count;
 3899#endif
 3900                if (boundCount == 1)
 3901                {
 3902                    if (!TryEmit(bounds.GetArgument(0), paramExprs, il, ref closure, setup, parent))
 3903                        return false;
 3904                    var elemType = expr.Type.GetElementType();
 3905                    if (elemType == null)
 3906                        return false;
 3907                    il.Demit(OpCodes.Newarr, elemType);
 3908                }
 3909                else
 3910                {
 3911                    for (var i = 0; i < boundCount; i++)
 3912                        if (!TryEmit(bounds.GetArgument(i), paramExprs, il, ref closure, setup, parent))
 3913                            return false;
 3914                    il.Demit(OpCodes.Newobj, expr.Type.GetTypeInfo().DeclaredConstructors.GetFirst());
 3915                }
 3916                return true;
 3917            }
 3918
 3919#if LIGHT_EXPRESSION
 3920            private static bool EmitNewArrayInit(NewArrayExpression expr, IParameterProvider paramExprs,
 3921                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 3922            {
 3923#else
 3924            private static bool EmitNewArrayInit(NewArrayExpression expr, IReadOnlyList<PE> paramExprs,
 3925                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 3926            {
 3927#endif
 3928                var arrayType = expr.Type;
 3929                if (arrayType.GetArrayRank() > 1)
 3930                    return false; // todo: @feature multi-dimensional array initializers are not supported yet, they als
 3931
 3932                var elemType = arrayType.GetElementType();
 3933                if (elemType == null)
 3934                    return false;
 3935
 3936#if LIGHT_EXPRESSION
 3937                var elems = (IArgumentProvider)expr;
 3938                var elemCount = elems.ArgumentCount;
 3939#else
 3940                var elems = expr.Expressions;
 3941                var elemCount = elems.Count;
 3942#endif
 3943                EmitLoadConstantInt(il, elemCount); // emit the length of the array calculated from the number of initia
 3944                il.Demit(OpCodes.Newarr, elemType);
 3945
 3946                var isElemOfValueType = elemType.IsValueType;
 3947                for (var i = 0; i < elemCount; i++)
 3948                {
 3949                    il.Demit(OpCodes.Dup);
 3950                    EmitLoadConstantInt(il, i);
 3951                    if (isElemOfValueType) // loading element address for later copying of value into it.
 3952                    {
 3953                        il.Demit(OpCodes.Ldelema, elemType);
 3954                        if (!TryEmit(elems.GetArgument(i), paramExprs, il, ref closure, setup, parent))
 3955                            return false;
 3956                        il.Demit(OpCodes.Stobj, elemType); // store element of value type by array element address
 3957                    }
 3958                    else
 3959                    {
 3960                        if (!TryEmit(elems.GetArgument(i), paramExprs, il, ref closure, setup, parent))
 3961                            return false;
 3962                        il.Demit(OpCodes.Stelem_Ref);
 3963                    }
 3964                }
 3965                return true;
 3966            }
 3967
 3968#if LIGHT_EXPRESSION
 3969            private static bool EmitMemberInit(MemberInitExpression expr, IParameterProvider paramExprs, ILGenerator il,
 3970                CompilerFlags setup, ParentFlags parent)
 3971#else
 3972            private static bool EmitMemberInit(MemberInitExpression expr, IReadOnlyList<PE> paramExprs, ILGenerator il, 
 3973                CompilerFlags setup, ParentFlags parent)
 3974#endif
 3975            {
 3976                var valueVarIndex = -1;
 3977                var exprType = expr.Type;
 3978                if (exprType.IsValueType)
 3979                    valueVarIndex = il.GetNextLocalVarIndex(exprType);
 3980
 3981                var newExpr = expr.NewExpression;
 3982#if LIGHT_EXPRESSION
 3983                if (newExpr == null)
 3984                {
 3985                    if (!TryEmit(expr.Expression, paramExprs, il, ref closure, setup, parent))
 3986                        return false;
 3987                    if (valueVarIndex != -1)
 3988                        EmitStoreLocalVariable(il, valueVarIndex);
 3989                }
 3990                else
 3991#endif
 3992                {
 3993#if SUPPORTS_ARGUMENT_PROVIDER
 3994                    var argExprs = (IArgumentProvider)newExpr;
 3995#else
 3996                    var argExprs = newExpr.Arguments;
 3997#endif
 3998                    var argCount = argExprs.GetCount();
 3999                    if (argCount > 0)
 4000                    {
 4001                        var args = newExpr.Constructor.GetParameters();
 4002                        for (var i = 0; i < argCount; i++)
 4003                            if (!TryEmit(argExprs.GetArgument(i), paramExprs, il, ref closure, setup, parent,
 4004                                args[i].ParameterType.IsByRef ? i : -1))
 4005                                return false;
 4006                    }
 4007
 4008                    if (newExpr.Constructor != null)
 4009                    {
 4010                        il.Demit(OpCodes.Newobj, newExpr.Constructor);
 4011                        if (valueVarIndex != -1)
 4012                            EmitStoreLocalVariable(il, valueVarIndex);
 4013                    }
 4014                    else if (valueVarIndex != -1)
 4015                        InitValueTypeVariable(il, exprType, valueVarIndex);
 4016                    else
 4017                        return false; // null constructor and not a value type, better to fallback
 4018                }
 4019
 4020#if LIGHT_EXPRESSION
 4021                var bindings = (IArgumentProvider<MemberBinding>)expr;
 4022                var bindCount = bindings.ArgumentCount;
 4023#else
 4024                var bindings = expr.Bindings;
 4025                var bindCount = bindings.Count;
 4026#endif
 4027                for (var i = 0; i < bindCount; i++)
 4028                {
 4029                    var binding = bindings.GetArgument(i);
 4030                    if (binding.BindingType != MemberBindingType.Assignment) // todo: @feature is not supported yet
 4031                        return false;
 4032
 4033                    if (valueVarIndex != -1) // load local value address, to set its members
 4034                        EmitLoadLocalVariableAddress(il, valueVarIndex);
 4035                    else
 4036                        il.Demit(OpCodes.Dup); // duplicate member owner on stack
 4037
 4038                    if (!TryEmit(((MemberAssignment)binding).Expression, paramExprs, il, ref closure, setup, parent) ||
 4039                        !EmitMemberSet(il, binding.Member))
 4040                        return false;
 4041                }
 4042
 4043                if (valueVarIndex != -1)
 4044                    EmitLoadLocalVariable(il, valueVarIndex);
 4045                return true;
 4046            }
 4047
 4048            [MethodImpl((MethodImplOptions)256)]
 4049            private static bool TryEmitPropertySet(ILGenerator il, PropertyInfo prop)
 4050            {
 4051                var method = prop.SetMethod;
 4052                return method != null && EmitMethodCallOrVirtualCall(il, method);
 4053            }
 4054
 4055            [MethodImpl((MethodImplOptions)256)]
 4056            private static bool EmitFieldSet(ILGenerator il, FieldInfo field)
 4057            {
 4058                il.Demit(field.IsStatic ? OpCodes.Stsfld : OpCodes.Stfld, field);
 4059                return true;
 4060            }
 4061
 4062            [MethodImpl((MethodImplOptions)256)]
 4063            private static bool EmitMemberSet(ILGenerator il, MemberInfo member) =>
 4064                member is PropertyInfo pr ? TryEmitPropertySet(il, pr) :
 4065                member is FieldInfo field ? EmitFieldSet(il, field) :
 4066                false;
 4067
 4068#if LIGHT_EXPRESSION
 4069            private static bool TryEmitListInit(ListInitExpression expr, IParameterProvider paramExprs, ILGenerator il, 
 4070                CompilerFlags setup, ParentFlags parent)
 4071#else
 4072            private static bool TryEmitListInit(ListInitExpression expr, IReadOnlyList<PE> paramExprs, ILGenerator il, r
 4073                CompilerFlags setup, ParentFlags parent)
 4074#endif
 4075            {
 4076                var valueVarIndex = -1;
 4077                var exprType = expr.Type;
 4078                if (exprType.IsValueType)
 4079                    valueVarIndex = il.GetNextLocalVarIndex(exprType);
 4080
 4081                var newExpr = expr.NewExpression;
 4082#if SUPPORTS_ARGUMENT_PROVIDER
 4083                var argExprs = (IArgumentProvider)newExpr;
 4084#else
 4085                var argExprs = newExpr.Arguments;
 4086#endif
 4087                var argCount = argExprs.GetCount();
 4088                if (argCount > 0)
 4089                {
 4090                    var args = newExpr.Constructor.GetParameters();
 4091                    for (var i = 0; i < argCount; i++)
 4092                        if (!TryEmit(argExprs.GetArgument(i), paramExprs, il, ref closure, setup, parent,
 4093                            args[i].ParameterType.IsByRef ? i : -1))
 4094                            return false;
 4095                }
 4096
 4097                if (newExpr.Constructor != null)
 4098                {
 4099                    il.Demit(OpCodes.Newobj, newExpr.Constructor);
 4100                    if (valueVarIndex != -1)
 4101                        EmitStoreLocalVariable(il, valueVarIndex);
 4102                }
 4103                else if (valueVarIndex != -1)
 4104                    InitValueTypeVariable(il, exprType, valueVarIndex);
 4105                else
 4106                    return false; // null constructor and not a value type, better to fallback
 4107
 4108                var inits = expr.Initializers;
 4109                var initCount = inits.Count;
 4110                var ok = true;
 4111
 4112                // see the TryEmitMethodCall for the reason of the callFlags
 4113                var callFlags = (parent
 4114                    & ~(ParentFlags.IgnoreResult | ParentFlags.MemberAccess | ParentFlags.InstanceAccess |
 4115                        ParentFlags.LambdaCall | ParentFlags.ReturnByRef))
 4116                    | ParentFlags.Call;
 4117                for (var i = 0; i < initCount; ++i)
 4118                {
 4119                    if (valueVarIndex != -1) // load local value address, to set its members
 4120                        EmitLoadLocalVariableAddress(il, valueVarIndex);
 4121                    else
 4122                        il.Demit(OpCodes.Dup); // duplicate member owner on stack
 4123
 4124                    var elemInit = inits.GetArgument(i);
 4125                    var method = elemInit.AddMethod;
 4126                    var methodParams = method.GetParameters();
 4127#if LIGHT_EXPRESSION
 4128                    var addArgs = (IArgumentProvider)elemInit;
 4129                    var addArgCount = elemInit.ArgumentCount;
 4130#else
 4131                    var addArgs = elemInit.Arguments;
 4132                    var addArgCount = addArgs.Count;
 4133#endif
 4134                    for (var a = 0; ok && a < addArgCount; ++a)
 4135                        ok = TryEmit(addArgs.GetArgument(a), paramExprs, il, ref closure, setup, callFlags, methodParams
 4136
 4137                    if (!exprType.IsValueType)
 4138                        ok = EmitMethodCallOrVirtualCall(il, method);
 4139                    else if (!method.IsVirtual // #251 - no need for constrained or virtual call because it is already b
 4140                        || method.DeclaringType == exprType)
 4141                        ok = EmitMethodCall(il, method);
 4142                    else
 4143                    {
 4144                        il.Demit(OpCodes.Constrained, exprType); // todo: @clarify it is a value type so... can we de-vi
 4145                        ok = EmitVirtualMethodCall(il, method);
 4146                    }
 4147                }
 4148
 4149                if (valueVarIndex != -1)
 4150                    EmitLoadLocalVariable(il, valueVarIndex);
 4151                return ok;
 4152            }
 4153
 4154            // the `right = null` argument indicates the increment/decrement operation
 4155            private static bool TryEmitArithmeticAndOrAssign(
 4156                Expression left, Expression right, Type exprType, ExpressionType nodeType, bool isPost,
 4157#if LIGHT_EXPRESSION
 4158                IParameterProvider paramExprs,
 4159#else
 4160                IReadOnlyList<PE> paramExprs,
 4161#endif
 4162                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 4163            {
 4164                // we need the result variable and the time of Post/Pre when to store it only if the result is not ignor
 4165                var resultVar = -1;
 4166                if (!parent.IgnoresResult())
 4167                    resultVar = il.GetNextLocalVarIndex(exprType);
 4168
 4169                switch (left.NodeType)
 4170                {
 4171                    case ExpressionType.Parameter:
 4172                        if (!isPost)
 4173                            return TryEmitAssignToParameterOrVariable((ParameterExpression)left, right,
 4174                                nodeType, isPost, exprType, paramExprs, il, ref closure, setup, parent, resultVar);
 4175
 4176                        // todo: @wip split for now between the Increment/Decrement and the rest
 4177                        var p = (ParameterExpression)left;
 4178#if LIGHT_EXPRESSION
 4179                        var paramExprCount = paramExprs.ParameterCount;
 4180#else
 4181                        var paramExprCount = paramExprs.Count;
 4182#endif
 4183                        var paramIndex = -1;
 4184                        var localVarIndex = closure.GetDefinedLocalVarOrDefault(p);
 4185                        if (localVarIndex != -1)
 4186                            EmitLoadLocalVariable(il, localVarIndex);
 4187                        else
 4188                        {
 4189                            paramIndex = paramExprCount - 1;
 4190                            while (paramIndex != -1 && !ReferenceEquals(paramExprs.GetParameter(paramIndex), p)) --param
 4191                            if (paramIndex == -1)
 4192                                return false;
 4193                            if ((closure.Status & ClosureStatus.ShouldBeStaticMethod) == 0)
 4194                                ++paramIndex;
 4195                            EmitLoadArg(il, paramIndex);
 4196                            if (p.IsByRef)
 4197                                EmitLoadIndirectlyByRef(il, p.Type);
 4198                        }
 4199
 4200                        if (resultVar != -1 & isPost)
 4201                            EmitStoreAndLoadLocalVariable(il, resultVar); // for the post increment/decrement save the n
 4202
 4203                        EmitIncOrDec(il, nodeType == ExpressionType.Add);
 4204
 4205                        if (resultVar != -1 & !isPost)
 4206                            EmitStoreAndLoadLocalVariable(il, resultVar);
 4207
 4208                        if (localVarIndex != -1)
 4209                            EmitStoreLocalVariable(il, localVarIndex); // store incremented value into the local value;
 4210                        else if (p.IsByRef)
 4211                        {
 4212                            var incrementedVar = il.GetNextLocalVarIndex(exprType);
 4213                            EmitStoreLocalVariable(il, incrementedVar);
 4214                            EmitLoadArg(il, paramIndex);
 4215                            EmitLoadLocalVariable(il, incrementedVar);
 4216                            EmitStoreIndirectlyByRef(il, exprType);
 4217                        }
 4218                        else
 4219                            il.Demit(OpCodes.Starg_S, paramIndex);
 4220                        break;
 4221
 4222                    case ExpressionType.ArrayIndex:
 4223                        throw new InvalidOperationException("ArrayIndex is not supported for the left part of the assign
 4224
 4225                    case ExpressionType.MemberAccess:
 4226                    case ExpressionType.Index:
 4227                        var leftMemberExpr = left as MemberExpression;
 4228                        var orLeftIndexExpr = left as IndexExpression;
 4229
 4230                        // return early for not supported types of left value to avoid multiple checks below
 4231                        if (leftMemberExpr == null & orLeftIndexExpr == null)
 4232                            return false;
 4233
 4234                        var indexArgCount = -1;
 4235#if SUPPORTS_ARGUMENT_PROVIDER
 4236                        IArgumentProvider indexArgs = null;
 4237#else
 4238                        IReadOnlyList<Expression> indexArgs = null;
 4239#endif
 4240                        if (orLeftIndexExpr != null)
 4241                        {
 4242#if SUPPORTS_ARGUMENT_PROVIDER
 4243                            indexArgs = (IArgumentProvider)orLeftIndexExpr;
 4244#else
 4245                            indexArgs = orLeftIndexExpr.Arguments;
 4246#endif
 4247                            indexArgCount = indexArgs.GetCount();
 4248                            if (indexArgCount > 4)
 4249                                return false; // todo: @feature more than 4 index arguments are not supported, and proba
 4250                        }
 4251
 4252                        var objExpr = leftMemberExpr != null ? leftMemberExpr.Expression : orLeftIndexExpr.Object;
 4253
 4254                        // Remove the InstanceCall because we need to operate on the (nullable) field value and not on `
 4255                        // We may avoid it in case of not returning the value or PreIncrement/PreDecrement, but let's do
 4256                        var baseFlags = parent &
 4257                            ~(ParentFlags.IgnoreResult | ParentFlags.InstanceCall |
 4258                              ParentFlags.LambdaCall | ParentFlags.ReturnByRef);
 4259                        var rightOnlyFlags = baseFlags | ParentFlags.AssignmentRightValue;
 4260
 4261
 4262                        var memberOrIndexFlags = leftMemberExpr != null ? ParentFlags.MemberAccess : ParentFlags.IndexAc
 4263                        var leftArLeastFlags = baseFlags | ParentFlags.AssignmentLeftValue | memberOrIndexFlags;
 4264
 4265                        var leftIsByAddress = false;
 4266                        if (nodeType == ExpressionType.Assign)
 4267                        {
 4268                            Debug.Assert(right != null);
 4269                            var rightType = right.Type;
 4270
 4271                            // if the right part is the block or alike, it is better from the complexity perspective
 4272                            // to emit it first and then restore the assignment target from var and assign the value
 4273                            var rightVar = -1;
 4274                            if (right.NodeType.IsBlockLikeOrConditional() ||
 4275                                right.NodeType == ExpressionType.Invoke)
 4276                            {
 4277                                if (!TryEmit(right, paramExprs, il, ref closure, setup, rightOnlyFlags))
 4278                                    return false;
 4279                                if (closure.LastEmitIsAddress)
 4280                                    EmitLoadIndirectlyByRef(il, rightType);
 4281                                rightVar = resultVar != -1 ? resultVar : il.GetNextLocalVarIndex(rightType);
 4282                                EmitStoreLocalVariable(il, rightVar);
 4283                            }
 4284
 4285                            // Emit the left-value instance and index(es) (for the index access)
 4286                            if (leftMemberExpr != null)
 4287                            {
 4288                                if (objExpr != null &&
 4289                                    !TryEmit(objExpr, paramExprs, il, ref closure, setup, leftArLeastFlags | ParentFlags
 4290                                    return false;
 4291                            }
 4292                            else
 4293                            {
 4294                                Debug.Assert(orLeftIndexExpr != null);
 4295                                if (objExpr != null)
 4296                                {
 4297                                    var isIndexerAMethodCall = indexArgCount > 1 | orLeftIndexExpr.Indexer != null;
 4298                                    var objFlags = isIndexerAMethodCall ? ParentFlags.InstanceCall : ParentFlags.Instanc
 4299                                    if (!TryEmit(objExpr, paramExprs, il, ref closure, setup, objFlags | ParentFlags.Ass
 4300                                        return false;
 4301                                }
 4302                                for (var i = 0; i < indexArgCount; i++)
 4303                                    if (!TryEmit(indexArgs.GetArgument(i), paramExprs, il, ref closure, setup, baseFlags
 4304                                        return false;
 4305                            }
 4306
 4307                            // Load already emitted or emit the right-value normally after the left to be assigned
 4308                            if (rightVar != -1)
 4309                            {
 4310                                EmitLoadLocalVariable(il, rightVar);
 4311                            }
 4312                            else
 4313                            {
 4314                                if (!TryEmit(right, paramExprs, il, ref closure, setup, rightOnlyFlags))
 4315                                    return false;
 4316                                if (resultVar != -1)
 4317                                    EmitStoreAndLoadLocalVariable(il, resultVar);
 4318                            }
 4319
 4320                            if (leftMemberExpr != null)
 4321                            {
 4322                                if (!EmitMemberSet(il, leftMemberExpr.Member))
 4323                                    return false;
 4324                            }
 4325                            else // if (leftIndexExpr != null)
 4326                            {
 4327                                var ok = orLeftIndexExpr.Indexer != null
 4328                                    ? EmitMethodCallOrVirtualCallCheckForNull(il, orLeftIndexExpr.Indexer.SetMethod)
 4329                                    : indexArgCount == 1
 4330                                        ? TryEmitArrayIndexSet(il, orLeftIndexExpr.Type) // one-dimensional array
 4331                                        : EmitMethodCallOrVirtualCallCheckForNull(il, objExpr?.Type.FindMethod("Set")); 
 4332                                if (!ok)
 4333                                    return false;
 4334                            }
 4335
 4336                            if (resultVar != -1)
 4337                                EmitLoadLocalVariable(il, resultVar);
 4338                            return true;
 4339                        }
 4340
 4341                        // Here we are at Arithmetic + Assign:
 4342                        // 1. First loading the left part as a part of right assignment,
 4343                        // 2. Loading the right value
 4344                        // 3. Do arithmetic operation
 4345                        // 4. Storing the result in the local variable
 4346                        // 5. Loading the left value for assignment
 4347                        // 6. Loading the stored arithmetic result
 4348                        // 7. Assign the result
 4349                        var leftOrRightNullableAreNullLabel = default(Label);
 4350                        var leftType = left.Type;
 4351                        if (leftMemberExpr != null)
 4352                        {
 4353                            if (!TryEmitMemberGet(leftMemberExpr, paramExprs, il, ref closure, setup,
 4354                                    leftArLeastFlags | ParentFlags.Arithmetic | ParentFlags.DupIt))
 4355                                return false;
 4356                        }
 4357                        else // if (leftIndexExpr != null)
 4358                        {
 4359                            // determine is the index essentially the method call to get/set value
 4360                            var isIndexerAMethodCall = indexArgCount > 1 | orLeftIndexExpr.Indexer != null;
 4361                            var objVar = -1;
 4362                            var objVarByAddress = false;
 4363                            if (objExpr != null)
 4364                            {
 4365                                var objFlags = isIndexerAMethodCall ? ParentFlags.InstanceCall : ParentFlags.InstanceAcc
 4366                                if (!TryEmit(objExpr, paramExprs, il, ref closure, setup, objFlags | ParentFlags.Arithme
 4367                                    return false;
 4368
 4369                                // required for calling the method on the value type parameter
 4370                                var objType = objExpr.Type;
 4371                                objVarByAddress = !closure.LastEmitIsAddress && objType.IsValueType && // todo: @wip avo
 4372                                    (objExpr.NodeType != ExpressionType.Parameter || !((ParameterExpression)objExpr).IsB
 4373                                if (objVarByAddress)
 4374                                    objVar = EmitStoreAndLoadLocalVariableAddress(il, objType);
 4375                                else
 4376                                {
 4377                                    if (objExpr is ParameterExpression pe && pe.IsByRef)
 4378                                        objType = objType.MakeByRefType();
 4379                                    objVar = EmitStoreAndLoadLocalVariable(il, objType);
 4380                                }
 4381                            }
 4382
 4383                            int indexArgVar0 = -1, indexArgVar1 = -1, indexArgVar2 = -1, indexArgVar3 = -1; // using sta
 4384                            for (var i = 0; i < indexArgCount; i++)
 4385                            {
 4386                                var indexArg = indexArgs.GetArgument(i);
 4387                                if (!TryEmit(indexArg, paramExprs, il, ref closure, setup, baseFlags))
 4388                                    return false;
 4389                                var indexArgVar = EmitStoreAndLoadLocalVariable(il, indexArg.Type);
 4390                                if (i == 0) indexArgVar0 = indexArgVar;
 4391                                else if (i == 1) indexArgVar1 = indexArgVar;
 4392                                else if (i == 2) indexArgVar2 = indexArgVar;
 4393                                else if (i == 3) indexArgVar3 = indexArgVar;
 4394                            }
 4395
 4396                            // repeat the load of the obj and index variables for the assignment here to avoid store and
 4397                            if (objExpr != null)
 4398                            {
 4399                                if (!objVarByAddress)
 4400                                    EmitLoadLocalVariable(il, objVar);
 4401                                else
 4402                                    EmitLoadLocalVariableAddress(il, objVar);
 4403                            }
 4404
 4405                            EmitLoadLocalVariable(il, indexArgVar0); // there is always at least one index argument
 4406                            if (indexArgVar1 != -1)
 4407                            {
 4408                                EmitLoadLocalVariable(il, indexArgVar1);
 4409                                if (indexArgVar2 != -1)
 4410                                    EmitLoadLocalVariable(il, indexArgVar2);
 4411                                if (indexArgVar3 != -1)
 4412                                    EmitLoadLocalVariable(il, indexArgVar3);
 4413                            }
 4414
 4415                            var ok = !isIndexerAMethodCall
 4416                                ? TryEmitArrayIndexGet(il, orLeftIndexExpr.Type, ref closure, baseFlags) // one-dimensio
 4417                                : orLeftIndexExpr.Indexer != null
 4418                                    ? EmitMethodCallOrVirtualCallCheckForNull(il, orLeftIndexExpr.Indexer.GetMethod)
 4419                                    : EmitMethodCallOrVirtualCallCheckForNull(il, objExpr?.Type.FindMethod("Get")); // m
 4420                            if (!ok)
 4421                                return false;
 4422                        }
 4423
 4424                        if (leftIsByAddress = closure.LastEmitIsAddress)
 4425                            EmitLoadIndirectlyByRef(il, leftType); // if the field is loaded by ref, it need to be loade
 4426
 4427                        var leftIsNullable = leftType.IsNullable();
 4428                        if (!leftIsNullable)
 4429                        {
 4430                            if (right == null) // optimization for the common increment/decrement case, indicated by usi
 4431                            {
 4432                                if (resultVar != -1 & isPost)
 4433                                    EmitStoreAndLoadLocalVariable(il, resultVar); // for the post increment/decrement sa
 4434                                EmitIncOrDec(il, nodeType == ExpressionType.Add);
 4435                                if (resultVar != -1 & !isPost)
 4436                                    EmitStoreAndLoadLocalVariable(il, resultVar);
 4437                            }
 4438                            else
 4439                            {
 4440                                var rightType = right.Type;
 4441                                if (!TryEmit(right, paramExprs, il, ref closure, setup, rightOnlyFlags))
 4442                                    return false;
 4443
 4444                                var rightIsNullable = rightType.IsNullable();
 4445                                if (rightIsNullable) // todo: @perf @clarify is it even possible to have left non-nullab
 4446                                {
 4447                                    var rightVar = EmitStoreAndLoadLocalVariableAddress(il, rightType);
 4448                                    il.Demit(OpCodes.Call, leftType.GetNullableHasValueGetterMethod());
 4449
 4450                                    il.Demit(OpCodes.Brfalse, leftOrRightNullableAreNullLabel = il.DefineLabel());
 4451
 4452                                    EmitLoadLocalVariableAddress(il, rightVar);
 4453                                    il.Demit(OpCodes.Ldfld, rightType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod()
 4454                                }
 4455
 4456                                if (!TryEmitArithmeticOperation(leftType, rightType, nodeType, exprType, il))
 4457                                    return false;
 4458                                if (resultVar != -1)
 4459                                    EmitStoreAndLoadLocalVariable(il, resultVar);
 4460                            }
 4461                        }
 4462                        else // if `leftIsNullable == true`
 4463                        {
 4464                            // Reuse the result variable for the field,
 4465                            // so it may be returned as the original value of field if nullable is `null` and we jump to
 4466                            var leftNullableVar = resultVar != -1 ? resultVar : il.GetNextLocalVarIndex(leftType);
 4467                            EmitStoreLocalVariable(il, leftNullableVar);
 4468
 4469                            if (right == null)
 4470                            {
 4471                                EmitLoadLocalVariableAddress(il, leftNullableVar);
 4472                                il.Demit(OpCodes.Call, leftType.GetNullableHasValueGetterMethod());
 4473
 4474                                il.Demit(OpCodes.Brfalse, leftOrRightNullableAreNullLabel = il.DefineLabel());
 4475
 4476                                EmitLoadLocalVariableAddress(il, leftNullableVar);
 4477                                il.Demit(OpCodes.Ldfld, leftType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod());
 4478
 4479                                EmitIncOrDec(il, nodeType == ExpressionType.Add);
 4480                            }
 4481                            else
 4482                            {
 4483                                // emit the right expression immediately after the left and then just process their resu
 4484                                var rightType = right.Type;
 4485                                if (!TryEmit(right, paramExprs, il, ref closure, setup, rightOnlyFlags))
 4486                                    return false;
 4487                                if (closure.LastEmitIsAddress)
 4488                                    EmitLoadIndirectlyByRef(il, rightType);
 4489
 4490                                var rightVar = EmitStoreLocalVariable(il, rightType);
 4491
 4492                                var rightIsNullable = rightType.IsNullable();
 4493                                if (!rightIsNullable) // todo: @perf @clarify if it is possible to have left nullable an
 4494                                {
 4495                                    EmitLoadLocalVariableAddress(il, leftNullableVar);
 4496                                    il.Demit(OpCodes.Call, leftType.GetNullableHasValueGetterMethod());
 4497
 4498                                    il.Demit(OpCodes.Brfalse, leftOrRightNullableAreNullLabel = il.DefineLabel());
 4499
 4500                                    EmitLoadLocalVariableAddress(il, leftNullableVar);
 4501                                    il.Demit(OpCodes.Ldfld, leftType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod())
 4502
 4503                                    EmitLoadLocalVariable(il, rightVar);
 4504                                }
 4505                                else
 4506                                {
 4507                                    EmitLoadLocalVariableAddress(il, leftNullableVar);
 4508                                    il.Demit(OpCodes.Call, leftType.GetNullableHasValueGetterMethod());
 4509
 4510                                    EmitLoadLocalVariableAddress(il, rightVar);
 4511                                    il.Demit(OpCodes.Call, rightType.GetNullableHasValueGetterMethod());
 4512                                    il.Demit(OpCodes.And);
 4513                                    il.Demit(OpCodes.Brfalse, leftOrRightNullableAreNullLabel = il.DefineLabel());
 4514
 4515                                    EmitLoadLocalVariableAddress(il, leftNullableVar);
 4516                                    il.Demit(OpCodes.Ldfld, leftType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod())
 4517
 4518                                    EmitLoadLocalVariableAddress(il, rightVar);
 4519                                    il.Demit(OpCodes.Ldfld, rightType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod()
 4520                                }
 4521
 4522                                if (!TryEmitArithmeticOperation(leftType, rightType, nodeType, exprType, il))
 4523                                    return false;
 4524                            }
 4525
 4526                            il.Demit(OpCodes.Newobj, leftType.GetNullableConstructor()); // wrap the result back into th
 4527                            if (resultVar != -1 & !isPost)
 4528                                EmitStoreAndLoadLocalVariable(il, resultVar);
 4529                        }
 4530
 4531                        if (leftIsByAddress)
 4532                            EmitStoreIndirectlyByRef(il, leftType);
 4533                        else if (leftMemberExpr != null)
 4534                        {
 4535                            if (!EmitMemberSet(il, leftMemberExpr.Member))
 4536                                return false;
 4537                        }
 4538                        else // if (leftIndexExpr != null)
 4539                        {
 4540                            var ok = orLeftIndexExpr.Indexer != null
 4541                                ? EmitMethodCallOrVirtualCallCheckForNull(il, orLeftIndexExpr.Indexer.SetMethod)
 4542                                : indexArgCount == 1
 4543                                    ? TryEmitArrayIndexSet(il, orLeftIndexExpr.Type) // one-dimensional array
 4544                                    : EmitMethodCallOrVirtualCallCheckForNull(il, objExpr?.Type.FindMethod("Set")); // m
 4545                            if (!ok)
 4546                                return false;
 4547                        }
 4548
 4549                        if (leftIsNullable)
 4550                        {
 4551                            // todo: @perf @simplify avoid the Dup and the Pop for this case via storing and loading loc
 4552                            if (leftIsByAddress | objExpr != null)
 4553                            {
 4554                                var skipPopLeftDuppedInstance = il.DefineLabel();
 4555                                il.Demit(OpCodes.Br_S, skipPopLeftDuppedInstance);
 4556                                il.DmarkLabel(leftOrRightNullableAreNullLabel); // jump here if nullables are null after
 4557
 4558                                il.Demit(OpCodes.Pop); // pop the dupped instance address or the field address, or the a
 4559
 4560                                if (orLeftIndexExpr != null)
 4561                                {
 4562                                    il.Demit(OpCodes.Pop); // pop the first index argument which is always present
 4563                                    if (indexArgCount > 1)
 4564                                    {
 4565                                        il.Demit(OpCodes.Pop);
 4566                                        if (indexArgCount > 2)
 4567                                        {
 4568                                            il.Demit(OpCodes.Pop);
 4569                                            if (indexArgCount > 3)
 4570                                                il.Demit(OpCodes.Pop); // pop the 4th last supported index argument
 4571                                        }
 4572                                    }
 4573                                }
 4574
 4575                                il.DmarkLabel(skipPopLeftDuppedInstance);
 4576                            }
 4577                            else
 4578                            {
 4579                                il.DmarkLabel(leftOrRightNullableAreNullLabel); // jump here if nullables are null after
 4580                            }
 4581                        }
 4582                        break;
 4583                    default:
 4584                        return false;
 4585                }
 4586
 4587                if (resultVar != -1)
 4588                    EmitLoadLocalVariable(il, resultVar);
 4589                return true;
 4590            }
 4591
 4592            private static ExpressionType AssignToArithmeticOrSelf(ExpressionType nodeType) => nodeType switch
 4593            {
 4594                ExpressionType.AddAssign => ExpressionType.Add,
 4595                ExpressionType.AddAssignChecked => ExpressionType.AddChecked,
 4596                ExpressionType.SubtractAssign => ExpressionType.Subtract,
 4597                ExpressionType.SubtractAssignChecked => ExpressionType.SubtractChecked,
 4598                ExpressionType.MultiplyAssign => ExpressionType.Multiply,
 4599                ExpressionType.MultiplyAssignChecked => ExpressionType.MultiplyChecked,
 4600                ExpressionType.DivideAssign => ExpressionType.Divide,
 4601                ExpressionType.ModuloAssign => ExpressionType.Modulo,
 4602                ExpressionType.PowerAssign => ExpressionType.Power,
 4603                ExpressionType.AndAssign => ExpressionType.And,
 4604                ExpressionType.OrAssign => ExpressionType.Or,
 4605                ExpressionType.ExclusiveOrAssign => ExpressionType.ExclusiveOr,
 4606                ExpressionType.LeftShiftAssign => ExpressionType.LeftShift,
 4607                ExpressionType.RightShiftAssign => ExpressionType.RightShift,
 4608                _ => nodeType
 4609            };
 4610
 4611            // the null `right` means the increment/decrement operation
 4612            private static bool TryEmitAssignToParameterOrVariable(
 4613                ParameterExpression left, Expression right, ExpressionType nodeType, bool isPost, Type exprType,
 4614#if LIGHT_EXPRESSION
 4615                IParameterProvider paramExprs,
 4616#else
 4617                IReadOnlyList<PE> paramExprs,
 4618#endif
 4619                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent, int resultVar = -1)
 4620            {
 4621#if LIGHT_EXPRESSION
 4622                var paramExprCount = paramExprs.ParameterCount;
 4623#else
 4624                var paramExprCount = paramExprs.Count;
 4625#endif
 4626                var ok = false;
 4627                var flags = parent & ~ParentFlags.IgnoreResult;
 4628
 4629                // First look if the left value is the local variable (in the current block) then store the right value 
 4630                var leftLocalVar = closure.GetDefinedLocalVarOrDefault(left);
 4631                if (leftLocalVar != -1)
 4632                {
 4633                    if (resultVar != -1 & isPost)
 4634                    {
 4635                        EmitLoadLocalVariable(il, leftLocalVar);
 4636                        EmitStoreLocalVariable(il, resultVar); // for the post increment/decrement save the non-incremen
 4637                    }
 4638
 4639                    var isLeftByRef = left.IsByRef;
 4640                    if (nodeType == ExpressionType.Assign)
 4641                    {
 4642                        var varFlags = flags | ParentFlags.AssignmentRightValue;
 4643                        if (isLeftByRef)
 4644                            varFlags |= ParentFlags.AssignmentByRef;
 4645                        ok = TryEmit(right, paramExprs, il, ref closure, setup, varFlags);
 4646                        if (resultVar != -1 & !isPost)
 4647                            EmitStoreAndLoadLocalVariable(il, resultVar);
 4648                        if (!isLeftByRef)
 4649                            EmitStoreLocalVariable(il, leftLocalVar);
 4650                    }
 4651                    else
 4652                    {
 4653                        ok = TryEmitArithmetic(left, right, nodeType, exprType, paramExprs, il, ref closure, setup, flag
 4654                        if (resultVar != -1 & !isPost)
 4655                            EmitStoreAndLoadLocalVariable(il, resultVar);
 4656                        if (isLeftByRef)
 4657                            EmitStoreIndirectlyByRef(il, exprType);
 4658                        else
 4659                            EmitStoreLocalVariable(il, leftLocalVar);
 4660                    }
 4661
 4662                    // assigning the new value into the already closed variable - it enables the recursive nested lambda
 4663                    var nestedLambdasCount = closure.NestedLambdas.Count;
 4664                    for (var i = 0; i < nestedLambdasCount; ++i)
 4665                        EmitStoreAssignedLeftVarIntoClosureArray(il, closure.NestedLambdas.Items[i], left, leftLocalVar)
 4666
 4667                    if (resultVar != -1)
 4668                        EmitLoadLocalVariable(il, resultVar);
 4669                    return ok;
 4670                }
 4671
 4672                // If not the variable, then look if it is the passed parameter - yes it is bad but you can assign to th
 4673                var paramIndex = paramExprCount - 1;
 4674                while (paramIndex != -1 && !ReferenceEquals(paramExprs.GetParameter(paramIndex), left)) --paramIndex;
 4675                if (paramIndex != -1)
 4676                {
 4677                    if ((closure.Status & ClosureStatus.ShouldBeStaticMethod) == 0)
 4678                        ++paramIndex; // shift parameter index by one, because the first one will be closure
 4679
 4680                    var isLeftByRef = left.IsByRef;
 4681                    if (isLeftByRef)
 4682                        EmitLoadArg(il, paramIndex);
 4683
 4684                    if (resultVar != -1 & isPost)
 4685                        EmitStoreAndLoadLocalVariable(il, resultVar); // for the post increment/decrement save the non-i
 4686
 4687                    ok = nodeType == ExpressionType.Assign
 4688                        ? TryEmit(right, paramExprs, il, ref closure, setup, flags)
 4689                        : TryEmitArithmetic(left, right, nodeType, exprType, paramExprs, il, ref closure, setup, flags);
 4690
 4691                    if (resultVar != -1 & !isPost)
 4692                        EmitStoreAndLoadLocalVariable(il, resultVar);
 4693
 4694                    if (isLeftByRef)
 4695                        EmitStoreIndirectlyByRef(il, left.Type);
 4696                    else
 4697                        il.Demit(OpCodes.Starg_S, paramIndex);
 4698
 4699                    if (resultVar != -1)
 4700                        EmitLoadLocalVariable(il, resultVar);
 4701                    return ok;
 4702                }
 4703
 4704                // check that it is a captured parameter by closure
 4705                var nonPassedParamIndex = closure.NonPassedParameters.TryGetIndex(left, default(RefEq<ParameterExpressio
 4706                if (nonPassedParamIndex == -1)
 4707                    return false;
 4708
 4709                if (nodeType == ExpressionType.Assign)
 4710                {
 4711                    if (!TryEmit(right, paramExprs, il, ref closure, setup, flags))
 4712                        return false;
 4713                    if (right is ParameterExpression rp && rp.IsByRef)
 4714                        EmitLoadIndirectlyByRef(il, rp.Type);
 4715
 4716                    var rightVar = resultVar != -1 ? resultVar : il.GetNextLocalVarIndex(exprType);
 4717                    EmitStoreLocalVariable(il, rightVar);
 4718
 4719                    // load array field and param item index
 4720                    il.Demit(OpCodes.Ldarg_0); // load closure as it is always an argument zero
 4721                    il.Demit(OpCodes.Ldfld, ArrayClosureWithNonPassedParamsField);
 4722                    EmitLoadConstantInt(il, nonPassedParamIndex);
 4723
 4724                    EmitLoadLocalVariable(il, rightVar);
 4725
 4726                    il.TryEmitBoxOf(exprType);
 4727                    il.Demit(OpCodes.Stelem_Ref); // put the variable into array
 4728
 4729                    // assigning the new value into the already closed variable - it enables the recursive nested lambda
 4730                    var nestedLambdasCount = closure.NestedLambdas.Count;
 4731                    for (var i = 0; i < nestedLambdasCount; ++i)
 4732                        EmitStoreAssignedLeftVarIntoClosureArray(il, closure.NestedLambdas.Items[i], left, rightVar);
 4733
 4734                    if (resultVar != -1)
 4735                        EmitLoadLocalVariable(il, rightVar);
 4736                    return true;
 4737                }
 4738
 4739                if (resultVar != -1 & isPost)
 4740                {
 4741                    il.Demit(OpCodes.Ldarg_0); // load closure as it is always an argument zero
 4742                    il.Demit(OpCodes.Ldfld, ArrayClosureWithNonPassedParamsField);
 4743                    EmitLoadConstantInt(il, nonPassedParamIndex);
 4744                    il.Demit(OpCodes.Ldelem_Ref); // load the variable from array
 4745                    if (exprType.IsValueType)
 4746                        il.Demit(OpCodes.Unbox_Any, exprType);
 4747#if NETFRAMEWORK
 4748                    else
 4749                        il.Demit(OpCodes.Castclass, exprType);
 4750#endif
 4751                    EmitStoreLocalVariable(il, resultVar);
 4752                }
 4753
 4754                // todo: @perf optimize for the increment/decrement case
 4755                if (!TryEmitArithmetic(left, right, nodeType, exprType, paramExprs, il, ref closure, setup, flags))
 4756                    return false;
 4757
 4758                var arithmeticResultVar = resultVar != -1 ? resultVar : il.GetNextLocalVarIndex(exprType);
 4759                EmitStoreLocalVariable(il, arithmeticResultVar);
 4760
 4761                il.Demit(OpCodes.Ldarg_0); // load closure as it is always an argument zero
 4762                il.Demit(OpCodes.Ldfld, ArrayClosureWithNonPassedParamsField);
 4763                EmitLoadConstantInt(il, nonPassedParamIndex);
 4764
 4765                EmitLoadLocalVariable(il, arithmeticResultVar);
 4766
 4767                il.TryEmitBoxOf(exprType);
 4768                il.Demit(OpCodes.Stelem_Ref); // put the variable into array
 4769
 4770                if (resultVar != -1 & !isPost)
 4771                    EmitLoadLocalVariable(il, arithmeticResultVar);
 4772                return true;
 4773            }
 4774
 4775            private static void EmitStoreAssignedLeftVarIntoClosureArray(ILGenerator il, NestedLambdaInfo nestedLambdaIn
 4776            {
 4777                if (nestedLambdaInfo.NonPassedParamsVarIndex == 0)
 4778                    return;
 4779                var nonPassedParIndex = nestedLambdaInfo.NonPassedParameters.TryGetIndex(assignedLeftVar, default(RefEq<
 4780                if (nonPassedParIndex == -1)
 4781                    return;
 4782                EmitLoadLocalVariable(il, nestedLambdaInfo.NonPassedParamsVarIndex);
 4783                EmitLoadConstantInt(il, nonPassedParIndex);
 4784                EmitLoadLocalVariable(il, assignedLeftVarIndex);
 4785                il.TryEmitBoxOf(assignedLeftVar.Type);
 4786                il.Demit(OpCodes.Stelem_Ref); // put the variable into non-passed parameters (variables) array
 4787            }
 4788
 4789            private static void EmitLoadIndirectlyByRef(ILGenerator il, Type type)
 4790            {
 4791                if (type.IsEnum)
 4792                    type = Enum.GetUnderlyingType(type);
 4793                switch (Type.GetTypeCode(type))
 4794                {
 4795                    case TypeCode.Boolean: il.Demit(OpCodes.Ldind_U1); break;
 4796                    case TypeCode.Char: il.Demit(OpCodes.Ldind_U1); break;
 4797                    case TypeCode.Byte: il.Demit(OpCodes.Ldind_U1); break;
 4798                    case TypeCode.SByte: il.Demit(OpCodes.Ldind_I1); break;
 4799                    case TypeCode.Int16: il.Demit(OpCodes.Ldind_I2); break;
 4800                    case TypeCode.Int32: il.Demit(OpCodes.Ldind_I4); break;
 4801                    case TypeCode.Int64: il.Demit(OpCodes.Ldind_I8); break;
 4802                    case TypeCode.Double: il.Demit(OpCodes.Ldind_R8); break;
 4803                    case TypeCode.Single: il.Demit(OpCodes.Ldind_R4); break;
 4804                    case TypeCode.UInt16: il.Demit(OpCodes.Ldind_U2); break;
 4805                    case TypeCode.UInt32: il.Demit(OpCodes.Ldind_U4); break;
 4806                    case TypeCode.UInt64: il.Demit(OpCodes.Ldobj, type); break;
 4807                    case TypeCode.String: il.Demit(OpCodes.Ldind_Ref); break;
 4808                    default:
 4809                        if (type == typeof(IntPtr) | type == typeof(UIntPtr))
 4810                            il.Demit(OpCodes.Ldind_I);
 4811                        else if (type.IsValueType)
 4812                            il.Demit(OpCodes.Ldobj, type);
 4813                        else
 4814                            il.Demit(OpCodes.Ldind_Ref);
 4815                        break;
 4816                }
 4817            }
 4818
 4819            private static void EmitStoreIndirectlyByRef(ILGenerator il, Type type)
 4820            {
 4821                if (type.IsEnum)
 4822                    type = Enum.GetUnderlyingType(type);
 4823                switch (Type.GetTypeCode(type))
 4824                {
 4825                    case TypeCode.Boolean: il.Demit(OpCodes.Stind_I1); break;
 4826                    case TypeCode.Char: il.Demit(OpCodes.Stind_I1); break;
 4827                    case TypeCode.Byte: il.Demit(OpCodes.Stind_I1); break;
 4828                    case TypeCode.SByte: il.Demit(OpCodes.Stind_I1); break;
 4829                    case TypeCode.Int16: il.Demit(OpCodes.Stind_I2); break;
 4830                    case TypeCode.Int32: il.Demit(OpCodes.Stind_I4); break;
 4831                    case TypeCode.Int64: il.Demit(OpCodes.Stind_I8); break;
 4832                    case TypeCode.Double: il.Demit(OpCodes.Stind_R8); break;
 4833                    case TypeCode.Single: il.Demit(OpCodes.Stind_R4); break;
 4834                    case TypeCode.String: il.Demit(OpCodes.Stind_Ref); break;
 4835                    case TypeCode.UInt16: il.Demit(OpCodes.Stind_I2); break;
 4836                    case TypeCode.UInt32: il.Demit(OpCodes.Stind_I4); break;
 4837                    case TypeCode.UInt64: il.Demit(OpCodes.Stind_I8); break;
 4838                    default:
 4839                        if (type == typeof(IntPtr) || type == typeof(UIntPtr))
 4840                            il.Demit(OpCodes.Stind_I);
 4841                        else if (type.IsValueType)
 4842                            il.Demit(OpCodes.Stobj, type);
 4843                        else
 4844                            il.Demit(OpCodes.Stind_Ref);
 4845                        break;
 4846                }
 4847            }
 4848
 4849            private static bool TryEmitArrayIndexGet(ILGenerator il, Type type, ref ClosureInfo closure, ParentFlags par
 4850            {
 4851                if (!type.IsValueType)
 4852                {
 4853                    il.Demit(OpCodes.Ldelem_Ref);
 4854                    return true;
 4855                }
 4856
 4857                // access the value type by address when it is used later for the member access, as instance in the meth
 4858                if ((parent & (ParentFlags.MemberAccess | ParentFlags.InstanceAccess | ParentFlags.AssignmentByRef)) != 
 4859                {
 4860                    il.Demit(OpCodes.Ldelema, type);
 4861                    closure.LastEmitIsAddress = true;
 4862                    return true;
 4863                }
 4864                // todo: @perf @simplify convert to switch on TypeCode
 4865                if (type == typeof(Int32))
 4866                    il.Demit(OpCodes.Ldelem_I4);
 4867                else if (type == typeof(Int64))
 4868                    il.Demit(OpCodes.Ldelem_I8);
 4869                else if (type == typeof(Int16))
 4870                    il.Demit(OpCodes.Ldelem_I2);
 4871                else if (type == typeof(SByte))
 4872                    il.Demit(OpCodes.Ldelem_I1);
 4873                else if (type == typeof(Single))
 4874                    il.Demit(OpCodes.Ldelem_R4);
 4875                else if (type == typeof(Double))
 4876                    il.Demit(OpCodes.Ldelem_R8);
 4877                else if (type == typeof(IntPtr))
 4878                    il.Demit(OpCodes.Ldelem_I);
 4879                else if (type == typeof(UIntPtr))
 4880                    il.Demit(OpCodes.Ldelem_I);
 4881                else if (type == typeof(Byte))
 4882                    il.Demit(OpCodes.Ldelem_U1);
 4883                else if (type == typeof(UInt16))
 4884                    il.Demit(OpCodes.Ldelem_U2);
 4885                else if (type == typeof(UInt32))
 4886                    il.Demit(OpCodes.Ldelem_U4);
 4887                else
 4888                    il.Demit(OpCodes.Ldelem, type);
 4889                return true;
 4890            }
 4891
 4892            private static bool TryEmitArrayIndexSet(ILGenerator il, Type elementType)
 4893            {
 4894                if (!elementType.IsValueType)
 4895                {
 4896                    il.Demit(OpCodes.Stelem_Ref);
 4897                    return true;
 4898                }
 4899
 4900                if (elementType == typeof(Int32))
 4901                    il.Demit(OpCodes.Stelem_I4);
 4902                else if (elementType == typeof(Int64))
 4903                    il.Demit(OpCodes.Stelem_I8);
 4904                else if (elementType == typeof(Int16))
 4905                    il.Demit(OpCodes.Stelem_I2);
 4906                else if (elementType == typeof(SByte))
 4907                    il.Demit(OpCodes.Stelem_I1);
 4908                else if (elementType == typeof(Single))
 4909                    il.Demit(OpCodes.Stelem_R4);
 4910                else if (elementType == typeof(Double))
 4911                    il.Demit(OpCodes.Stelem_R8);
 4912                else if (elementType == typeof(IntPtr))
 4913                    il.Demit(OpCodes.Stelem_I);
 4914                else if (elementType == typeof(UIntPtr))
 4915                    il.Demit(OpCodes.Stelem_I);
 4916                else
 4917                    il.Demit(OpCodes.Stelem, elementType);
 4918                return true;
 4919            }
 4920
 4921            private static bool TryEmitMethodCall(Expression expr,
 4922#if LIGHT_EXPRESSION
 4923                IParameterProvider paramExprs,
 4924#else
 4925                IReadOnlyList<PE> paramExprs,
 4926#endif
 4927                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent, int byRefIndex = -1)
 4928            {
 4929                var flags = ParentFlags.Call;
 4930                var callExpr = (MethodCallExpression)expr;
 4931                var objExpr = callExpr.Object;
 4932                var method = callExpr.Method;
 4933                var methodParams = method.GetParameters(); // todo: @perf @mem find how to avoid the call, look at `NewN
 4934
 4935                var objIsValueType = false;
 4936                var loadObjByAddress = false;
 4937                if (objExpr != null)
 4938                {
 4939                    if (!TryEmit(objExpr, paramExprs, il, ref closure, setup, flags | ParentFlags.InstanceAccess))
 4940                        return false;
 4941                    objIsValueType = objExpr.Type.IsValueType;
 4942                    loadObjByAddress = objIsValueType && objExpr.NodeType != ExpressionType.Parameter && !closure.LastEm
 4943                }
 4944
 4945                var parCount = methodParams.Length;
 4946                if (parCount == 0)
 4947                {
 4948                    if (loadObjByAddress)
 4949                        EmitStoreAndLoadLocalVariableAddress(il, objExpr.Type);
 4950                }
 4951                else
 4952                {
 4953#if SUPPORTS_ARGUMENT_PROVIDER
 4954                    var callArgs = (IArgumentProvider)callExpr;
 4955#else
 4956                    var callArgs = callExpr.Arguments;
 4957#endif
 4958                    if (!closure.ArgsContainingComplexExpression.Map.ContainsKey(callExpr))
 4959                    {
 4960                        if (loadObjByAddress)
 4961                            EmitStoreAndLoadLocalVariableAddress(il, objExpr.Type);
 4962
 4963                        for (var i = 0; i < parCount; i++)
 4964                        {
 4965                            var argExpr = callArgs.GetArgument(i);
 4966                            var parType = methodParams[i].ParameterType;
 4967                            if (!TryEmit(argExpr, paramExprs, il, ref closure, setup, flags, parType.IsByRef ? i : -1))
 4968                                return false;
 4969                        }
 4970                    }
 4971                    else
 4972                    {
 4973                        // don't forget to store the object into the variable first, before emitting the arguments
 4974                        var objVar = objExpr == null ? -1 : EmitStoreLocalVariable(il, objExpr.Type);
 4975
 4976                        SmallList<int, Stack8<int>> argVars = default;
 4977                        for (var i = 0; i < methodParams.Length; i++)
 4978                        {
 4979                            var argExpr = callArgs.GetArgument(i);
 4980                            var parType = methodParams[i].ParameterType;
 4981                            if (!TryEmit(argExpr, paramExprs, il, ref closure, setup, flags, parType.IsByRef ? i : -1))
 4982                                return false;
 4983                            argVars.Add(EmitStoreLocalVariable(il, parType));
 4984                        }
 4985
 4986                        // restore the object and the args from the variables in the proper order to emit the call
 4987                        if (objExpr != null)
 4988                        {
 4989                            if (loadObjByAddress)
 4990                                EmitLoadLocalVariableAddress(il, objVar);
 4991                            else
 4992                                EmitLoadLocalVariable(il, objVar);
 4993                        }
 4994
 4995                        for (var i = 0; i < methodParams.Length; i++)
 4996                            EmitLoadLocalVariable(il, argVars[i]);
 4997                    }
 4998                }
 4999
 5000                var ok = true;
 5001                if (!objIsValueType)
 5002                    ok = EmitMethodCallOrVirtualCall(il, method);
 5003                else if (method.DeclaringType != typeof(Enum) &&
 5004                    (!method.IsVirtual ||
 5005                    method.DeclaringType == objExpr.Type ||
 5006                    objExpr is ParameterExpression pe && pe.IsByRef))
 5007                    ok = EmitMethodCall(il, method);
 5008                else
 5009                {
 5010                    il.Demit(OpCodes.Constrained, objExpr.Type);
 5011                    ok = EmitVirtualMethodCall(il, method);
 5012                }
 5013
 5014                if (byRefIndex != -1)
 5015                    EmitStoreAndLoadLocalVariableAddress(il, method.ReturnType);
 5016
 5017                if (parent.IgnoresResult() && method.ReturnType != typeof(void))
 5018                    il.Demit(OpCodes.Pop);
 5019
 5020                closure.LastEmitIsAddress = false;
 5021                return ok;
 5022            }
 5023
 5024            public static bool TryEmitMemberGet(MemberExpression expr,
 5025#if LIGHT_EXPRESSION
 5026                IParameterProvider paramExprs,
 5027#else
 5028                IReadOnlyList<PE> paramExprs,
 5029#endif
 5030                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent, int byRefIndex = -1)
 5031            {
 5032                var objExpr = expr.Expression;
 5033                if (expr.Member is PropertyInfo prop)
 5034                {
 5035                    if (objExpr != null)
 5036                    {
 5037                        var p = (parent | ParentFlags.InstanceCall)
 5038                            // removing ParentFlags.MemberAccess here because we are calling the method instead of acces
 5039                            & ~(ParentFlags.IgnoreResult | ParentFlags.MemberAccess | ParentFlags.DupIt |
 5040                                ParentFlags.LambdaCall | ParentFlags.ReturnByRef);
 5041
 5042                        if (!TryEmit(objExpr, paramExprs, il, ref closure, setup, p))
 5043                            return false;
 5044
 5045                        if ((parent & ParentFlags.DupIt) != 0) // just duplicate the whatever is emitted for object
 5046                            il.Demit(OpCodes.Dup);
 5047                        else
 5048                            // Value type special treatment to load address of value instance in order to call a method.
 5049                            // For the parameters, we will skip the address loading because the `LastEmitIsAddress == tr
 5050                            // so the condition here will be skipped
 5051                            if (!closure.LastEmitIsAddress && objExpr.Type.IsValueType)
 5052                            EmitStoreAndLoadLocalVariableAddress(il, objExpr.Type);
 5053                    }
 5054
 5055                    closure.LastEmitIsAddress = false;
 5056                    return EmitMethodCallOrVirtualCall(il, prop.GetMethod);
 5057                }
 5058
 5059                if (expr.Member is FieldInfo field)
 5060                {
 5061                    if (objExpr != null)
 5062                    {
 5063                        var p = (parent | ParentFlags.InstanceAccess | ParentFlags.MemberAccess)
 5064                            & ~ParentFlags.IgnoreResult & ~ParentFlags.DupIt;
 5065
 5066                        if (!TryEmit(objExpr, paramExprs, il, ref closure, setup, p))
 5067                            return false;
 5068
 5069                        if (parent.IgnoresResult())
 5070                        {
 5071                            il.Demit(OpCodes.Pop); // pop the obj value - it is emitted only for the side effects
 5072                            return true;
 5073                        }
 5074
 5075                        // #248 indicates that expression is argument passed by ref to Call
 5076                        var isByAddress = byRefIndex != -1;
 5077
 5078                        // we are assigning to the field of ValueType so we need its address `val.Bar += 1`, #352
 5079                        if ((parent & ParentFlags.AssignmentLeftValue) != 0 && objExpr.Type.IsValueType)
 5080                            isByAddress = true;
 5081                        else
 5082                            // if the field is not used as an index, #302
 5083                            // or if the field is not accessed from the just constructed object `new Widget().DodgyValue
 5084                            if (((parent & ParentFlags.InstanceAccess) != 0 &
 5085                                (parent & (ParentFlags.IndexAccess | ParentFlags.Ctor)) == 0) && field.FieldType.IsValue
 5086                            isByAddress = true;
 5087
 5088                        // we don't need to duplicate the instance if we are working with the field address to save to i
 5089                        // so the field address should be Dupped instead for loading and then storing by-ref for assignm
 5090                        // (don't forget to Pop if the assignment should be skipped for nullable with `null` value)
 5091                        if ((parent & ParentFlags.DupIt) != 0 &
 5092                            (!isByAddress | (parent & ParentFlags.AssignmentLeftValue) == 0))
 5093                            il.Demit(OpCodes.Dup);
 5094
 5095                        closure.LastEmitIsAddress = isByAddress;
 5096                        if (!isByAddress)
 5097                        {
 5098                            if (objExpr.Type.IsEnum)
 5099                                EmitStoreAndLoadLocalVariableAddress(il, objExpr.Type);
 5100                            il.Demit(OpCodes.Ldfld, field);
 5101                        }
 5102                        else
 5103                        {
 5104                            il.Demit(OpCodes.Ldflda, field);
 5105                            if ((parent & ParentFlags.AssignmentLeftValue) != 0)
 5106                                il.Demit(OpCodes.Dup);
 5107                        }
 5108                    }
 5109                    else if (field.IsLiteral)
 5110                    {
 5111                        if (parent.IgnoresResult())
 5112                            return true; // do nothing
 5113                        var fieldValue = field.GetValue(null);
 5114                        if (fieldValue != null)
 5115                            return TryEmitConstant(false, null, field.FieldType, fieldValue, il, ref closure);
 5116                        il.Demit(OpCodes.Ldnull);
 5117                    }
 5118                    else
 5119                    {
 5120                        if (parent.IgnoresResult())
 5121                            return true; // do nothing
 5122                        il.Demit(OpCodes.Ldsfld, field);
 5123                    }
 5124                    return true;
 5125                }
 5126                return false;
 5127            }
 5128
 5129            // ReSharper disable once FunctionComplexityOverflow
 5130#if LIGHT_EXPRESSION
 5131            private static bool TryEmitNestedLambda(LambdaExpression lambdaExpr, IParameterProvider outerParamExprs, ILG
 5132            {
 5133                var outerParamExprCount = outerParamExprs.ParameterCount;
 5134#else
 5135            private static bool TryEmitNestedLambda(LambdaExpression lambdaExpr, IReadOnlyList<PE> outerParamExprs, ILGe
 5136            {
 5137                var outerParamExprCount = outerParamExprs.Count;
 5138#endif
 5139                // First, find in closed compiled lambdas the one corresponding to the current lambda expression.
 5140                // Situation with not found lambda is not possible/exceptional,
 5141                // it means that we somehow skipped the lambda expression while collecting closure info.
 5142                var outerNestedLambdasCount = closure.NestedLambdas.Count;
 5143                var outerNestedLambdas = closure.NestedLambdas.Items;
 5144                var i = outerNestedLambdasCount - 1;
 5145                while (i != -1 && !outerNestedLambdas[i].HasTheSameLambdaExpression(lambdaExpr)) --i;
 5146                if (i == -1)
 5147                    return false;
 5148
 5149                ref var nestedLambdaInfo = ref outerNestedLambdas[i];
 5150                EmitLoadLocalVariable(il, nestedLambdaInfo.LambdaVarIndex);
 5151
 5152                // If lambda does not use any outer parameters to be set in closure, then we're done
 5153                var nonPassedParams = nestedLambdaInfo.NonPassedParameters;
 5154                if (nonPassedParams.Count == 0)
 5155                    return true;
 5156
 5157                //-------------------------------------------------------------------
 5158                // For the lambda with non-passed parameters (or variables) in closure
 5159
 5160                // Emit the NonPassedParams array for the non-passed parameters and variables
 5161                var nonPassedParamsCount = nonPassedParams.Count;
 5162                EmitLoadConstantInt(il, nonPassedParamsCount); // load the length of array
 5163                il.Demit(OpCodes.Newarr, typeof(object));
 5164                var nonPassedParamsVarIndex = EmitStoreAndLoadLocalVariable(il, typeof(object[]));
 5165                nestedLambdaInfo.NonPassedParamsVarIndex = (short)nonPassedParamsVarIndex;
 5166
 5167                // Store the NonPassedParams back into the NestedLambda wrapper for the #437.
 5168                // Also, it is needed to be able to assign the closed variable after the closure is passed to the lambda
 5169                // e.g. `var x = 1; var f = () => x + 1; x = 2; f();` expects 3, not 2
 5170                il.Demit(OpCodes.Stfld, NestedLambdaForNonPassedParams.NonPassedParamsField);
 5171
 5172                // Populate the NonPassedParams array
 5173                for (var nestedParamIndex = 0; nestedParamIndex < nonPassedParamsCount; ++nestedParamIndex)
 5174                {
 5175                    // todo: @wip move this code to where the assignment and by-ref parameter passing
 5176                    Debug.Assert(nestedParamIndex < 64, "Assume that we don't have more than 64 mutated non-passed param
 5177                    if (nonPassedParamsCount < 64)
 5178                        nestedLambdaInfo.NonPassedParamMutatedIndexBits |= 1UL << nestedParamIndex;
 5179
 5180                    // Load the array and index where to store the item
 5181                    EmitLoadLocalVariable(il, nonPassedParamsVarIndex);
 5182                    EmitLoadConstantInt(il, nestedParamIndex);
 5183
 5184                    var nestedParam = nonPassedParams.GetSurePresentItemRef(nestedParamIndex);
 5185                    var outerParamIndex = outerParamExprCount - 1;
 5186                    while (outerParamIndex != -1 && !ReferenceEquals(outerParamExprs.GetParameter(outerParamIndex), nest
 5187                        --outerParamIndex;
 5188                    if (outerParamIndex != -1) // load parameter from input outer params
 5189                    {
 5190                        // Add `+1` to index because the `0` index is for the closure argument
 5191                        EmitLoadArg(il, outerParamIndex + 1);
 5192                        il.TryEmitBoxOf(nestedParam.Type);
 5193                    }
 5194                    else // load parameter from outer closure or from the local variables
 5195                    {
 5196                        var outerLocalVarIndex = closure.GetDefinedLocalVarOrDefault(nestedParam);
 5197                        if (outerLocalVarIndex != -1) // it's a local variable
 5198                        {
 5199                            EmitLoadLocalVariable(il, outerLocalVarIndex);
 5200                            il.TryEmitBoxOf(nestedParam.Type);
 5201                        }
 5202                        else // it's a parameter from the outer closure
 5203                        {
 5204                            var outerNonPassedParamIndex = closure.NonPassedParameters.TryGetIndex(nestedParam, default(
 5205                            if (outerNonPassedParamIndex == -1)
 5206                                return false; // impossible, return error code 2 the same as in TryCollectInfo
 5207
 5208                            // Load the parameter from outer closure `Items` array
 5209                            il.Demit(OpCodes.Ldarg_0); // closure is always a first argument
 5210                            il.Demit(OpCodes.Ldfld, ArrayClosureWithNonPassedParamsField);
 5211                            EmitLoadConstantInt(il, outerNonPassedParamIndex);
 5212                            il.Demit(OpCodes.Ldelem_Ref);
 5213                        }
 5214                    }
 5215
 5216                    // Store the item into nested lambda array
 5217                    il.Demit(OpCodes.Stelem_Ref);
 5218                }
 5219
 5220                // Load the actual lambda delegate on stack
 5221                EmitLoadLocalVariable(il, nestedLambdaInfo.LambdaVarIndex);
 5222                il.Demit(OpCodes.Ldfld, NestedLambdaForNonPassedParams.NestedLambdaField);
 5223
 5224                // Load the nonPassedParams as a first argument of closure
 5225                EmitLoadLocalVariable(il, nonPassedParamsVarIndex);
 5226
 5227                // Load the constants as a second argument and call the closure constructor
 5228                var lambda = nestedLambdaInfo.Lambda;
 5229                if (lambda is NestedLambdaForNonPassedParamsWithConstants)
 5230                {
 5231                    EmitLoadLocalVariable(il, nestedLambdaInfo.LambdaVarIndex);
 5232                    il.Demit(OpCodes.Ldfld, NestedLambdaForNonPassedParamsWithConstants.ConstantsAndNestedLambdasField);
 5233                    il.Demit(OpCodes.Newobj, ArrayClosureWithNonPassedParamsAndConstantsCtor);
 5234                }
 5235                else
 5236                    il.Demit(OpCodes.Newobj, ArrayClosureWithNonPassedParamsCtor);
 5237
 5238                // Call the `Curry` method with the nested lambda and closure to produce a closed lambda with the expect
 5239                var lambdaType = (lambda is NestedLambdaForNonPassedParams lp ? lp.NestedLambda : lambda).GetType();
 5240                var lambdaTypeArgs = lambdaType.GetGenericArguments();
 5241                var nestedLambdaExpr = nestedLambdaInfo.LambdaExpression;
 5242                var closureMethod = nestedLambdaExpr.ReturnType == typeof(void)
 5243                    ? CurryClosureActions.Methods[lambdaTypeArgs.Length - 1].MakeGenericMethod(lambdaTypeArgs)
 5244                    : CurryClosureFuncs.Methods[lambdaTypeArgs.Length - 2].MakeGenericMethod(lambdaTypeArgs);
 5245
 5246                var ok = EmitMethodCall(il, closureMethod);
 5247
 5248                // Convert to the original possibly custom delegate type, see #308
 5249                if (closureMethod.ReturnType != nestedLambdaExpr.Type)
 5250                {
 5251                    il.Demit(OpCodes.Ldftn, closureMethod.ReturnType.FindDelegateInvokeMethod());
 5252                    il.Demit(OpCodes.Newobj, nestedLambdaExpr.Type.GetConstructors()[0]);
 5253                }
 5254
 5255                return ok;
 5256            }
 5257
 5258#if LIGHT_EXPRESSION
 5259            private static bool TryEmitInvoke(InvocationExpression expr, IParameterProvider paramExprs, ILGenerator il, 
 5260                CompilerFlags setup, ParentFlags parent)
 5261            {
 5262                var paramCount = paramExprs.ParameterCount;
 5263#else
 5264            private static bool TryEmitInvoke(InvocationExpression expr, IReadOnlyList<PE> paramExprs, ILGenerator il, r
 5265                CompilerFlags setup, ParentFlags parent)
 5266            {
 5267                var paramCount = paramExprs.Count;
 5268#endif
 5269#if SUPPORTS_ARGUMENT_PROVIDER
 5270                var argExprs = (IArgumentProvider)expr;
 5271#else
 5272                var argExprs = expr.Arguments;
 5273#endif
 5274                var argCount = argExprs.GetCount();
 5275                var invokedExpr = expr.Expression;
 5276                if ((setup & CompilerFlags.NoInvocationLambdaInlining) == 0 && invokedExpr is LambdaExpression lambdaExp
 5277                {
 5278                    parent |= ParentFlags.InlinedLambdaInvoke;
 5279
 5280                    ref var inlinedExpr = ref closure.InlinedLambdaInvocation.Map.AddOrGetValueRef(expr, out var found);
 5281                    Debug.Assert(found, "The invocation expression should be collected in TryCollectInfo but it is not")
 5282                    if (!found)
 5283                        return false;
 5284
 5285                    if (!TryEmit(inlinedExpr, paramExprs, il, ref closure, setup, parent))
 5286                        return false;
 5287
 5288                    if ((parent & ParentFlags.IgnoreResult) == 0 && inlinedExpr.Type != typeof(void))
 5289                    {
 5290                        // find if the variable with the result is exist in the label infos
 5291                        ref var label = ref closure.LambdaInvokeStackLabels.GetLabelOrInvokeIndexByTarget(expr, out var 
 5292                        if (labelFound)
 5293                        {
 5294                            var returnVariableIndexPlusOne = label.ReturnVariableIndexPlusOneAndIsDefined >>> 1;
 5295                            if (returnVariableIndexPlusOne != 0)
 5296                            {
 5297                                il.DmarkLabel(label.ReturnLabel);
 5298                                EmitLoadLocalVariable(il, returnVariableIndexPlusOne - 1);
 5299                            }
 5300                        }
 5301                    }
 5302                    return true;
 5303                }
 5304
 5305                if (!TryEmit(invokedExpr, paramExprs, il, ref closure, setup, parent & ~ParentFlags.IgnoreResult)) // re
 5306                    return false;
 5307
 5308                //if (lambda is ConstantExpression lambdaConst) // todo: @perf opportunity to optimize
 5309                //    delegateInvokeMethod = ((Delegate)lambdaConst.Value).GetMethodInfo();
 5310                //else
 5311                var delegateInvokeMethod = invokedExpr.Type.FindDelegateInvokeMethod(); // todo: @perf bad thingy
 5312                if (argCount != 0)
 5313                {
 5314                    var useResult = parent & ~ParentFlags.IgnoreResult & ~ParentFlags.InstanceAccess;
 5315                    var args = delegateInvokeMethod.GetParameters(); // todo: @perf avoid this if possible
 5316                    for (var i = 0; i < args.Length; ++i)
 5317                    {
 5318                        var argExpr = argExprs.GetArgument(i);
 5319                        if (!TryEmit(argExpr, paramExprs, il, ref closure, setup, useResult, args[i].ParameterType.IsByR
 5320                            return false;
 5321                    }
 5322                }
 5323
 5324                EmitMethodCall(il, delegateInvokeMethod);
 5325                if ((parent & ParentFlags.IgnoreResult) != 0 && delegateInvokeMethod.ReturnType != typeof(void))
 5326                    il.Demit(OpCodes.Pop);
 5327
 5328                return true;
 5329            }
 5330
 5331#if LIGHT_EXPRESSION
 5332            private static bool TryEmitSwitch(SwitchExpression expr, IParameterProvider paramExprs, ILGenerator il, ref 
 5333                CompilerFlags setup, ParentFlags parent)
 5334#else
 5335            private static bool TryEmitSwitch(SwitchExpression expr, IReadOnlyList<PE> paramExprs, ILGenerator il, ref C
 5336                CompilerFlags setup, ParentFlags parent)
 5337#endif
 5338            {
 5339                // todo: @perf #398 use switch statement for int comparison, e.g. if int difference is less or equal 3 -
 5340                var switchValueExpr = expr.SwitchValue;
 5341                var customEqualMethod = expr.Comparison;
 5342                var cases = expr.Cases;
 5343                var caseCount = cases.Count;
 5344                if (caseCount == 1 && expr.DefaultBody != null)
 5345                {
 5346                    // optimization for the single case
 5347                    // todo: @perf make a similar one for the two cases, probably use the two IfThenElses emit
 5348                    var cs0 = cases[0];
 5349                    if (cs0.TestValues.Count == 1)
 5350                    {
 5351                        Expression testExpr;
 5352                        if (customEqualMethod == null)
 5353                        {
 5354                            // todo: @perf avoid creation of the additional expression
 5355                            testExpr = Equal(switchValueExpr, cs0.TestValues[0]);
 5356                            if (Interpreter.TryInterpretBool(out var testResult, testExpr, setup))
 5357                                return TryEmit(testResult ? cs0.Body : expr.DefaultBody, paramExprs, il, ref closure, se
 5358                        }
 5359                        else
 5360                            testExpr = Call(customEqualMethod, switchValueExpr, cs0.TestValues[0]);
 5361
 5362                        return TryEmitConditional(testExpr, cs0.Body, expr.DefaultBody, paramExprs, il, ref closure, set
 5363                    }
 5364                }
 5365
 5366                var switchValueType = switchValueExpr.Type;
 5367                var switchValueIsNullable = switchValueType.IsNullable();
 5368                Type switchNullableUnderlyingValueType = null;
 5369                MethodInfo switchNullableHasValueMethod = null;
 5370                FieldInfo switchNullableUnsafeValueField = null;
 5371                if (switchValueIsNullable)
 5372                {
 5373                    switchNullableUnderlyingValueType = Nullable.GetUnderlyingType(switchValueType);
 5374                    switchNullableHasValueMethod = switchValueType.GetNullableHasValueGetterMethod();
 5375                    switchNullableUnsafeValueField = switchValueType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod();
 5376                }
 5377
 5378                var checkType = switchNullableUnderlyingValueType ?? switchValueType;
 5379                var equalityMethod = customEqualMethod != null
 5380                    ? customEqualMethod
 5381                    : !checkType.IsPrimitive && !checkType.IsEnum
 5382                        ? FindBinaryOperandMethod("op_Equality", switchValueType, switchValueType, switchValueType, type
 5383                        ?? _objectEqualsMethod
 5384                        : null;
 5385
 5386                var operandParent = parent & ~ParentFlags.IgnoreResult & ~ParentFlags.InstanceAccess;
 5387                var isEqualityMethodForUnderlyingNullable = false;
 5388                int param0ByRefIndex = -1, param1ByRefIndex = -1;
 5389                if (equalityMethod != null)
 5390                {
 5391                    operandParent |= ParentFlags.Call;
 5392                    var paramInfos = equalityMethod.GetParameters();
 5393                    Debug.Assert(paramInfos.Length == 2);
 5394                    var paramType = paramInfos[0].ParameterType;
 5395                    isEqualityMethodForUnderlyingNullable = paramType == switchNullableUnderlyingValueType;
 5396                    if (paramType.IsByRef)
 5397                        param0ByRefIndex = 0;
 5398                    if (paramInfos[1].ParameterType.IsByRef)
 5399                        param1ByRefIndex = 1;
 5400                }
 5401
 5402                // Emit the switch value once and store it in the local variable for comparison in cases below
 5403                if (!TryEmit(switchValueExpr, paramExprs, il, ref closure, setup, operandParent, param0ByRefIndex))
 5404                    return false;
 5405
 5406                if (caseCount == 0) // see #440
 5407                {
 5408                    il.Demit(OpCodes.Pop); // remove the switch value result
 5409                    return expr.DefaultBody == null ||
 5410                        TryEmit(expr.DefaultBody, paramExprs, il, ref closure, setup, parent);
 5411                }
 5412
 5413                var switchValueVar = EmitStoreLocalVariable(il, switchValueType);
 5414
 5415                var switchEndLabel = il.DefineLabel();
 5416                var caseLabels = new Label[caseCount];
 5417
 5418                for (var caseIndex = 0; caseIndex < caseLabels.Length; ++caseIndex)
 5419                {
 5420                    var cs = cases[caseIndex];
 5421                    var caseBodyLabel = il.DefineLabel();
 5422                    caseLabels[caseIndex] = caseBodyLabel;
 5423
 5424                    foreach (var caseTestValue in cs.TestValues)
 5425                    {
 5426                        if (!switchValueIsNullable)
 5427                        {
 5428                            EmitLoadLocalVariable(il, switchValueVar);
 5429                            if (!TryEmit(caseTestValue, paramExprs, il, ref closure, setup, operandParent, param1ByRefIn
 5430                                return false;
 5431                            if (equalityMethod == null)
 5432                            {
 5433                                il.Demit(OpCodes.Beq, caseBodyLabel);
 5434                                continue;
 5435                            }
 5436
 5437                            if (!EmitMethodCall(il, equalityMethod))
 5438                                return false;
 5439                            il.Demit(OpCodes.Brtrue, caseBodyLabel);
 5440                            continue;
 5441                        }
 5442
 5443                        if (equalityMethod != null & !isEqualityMethodForUnderlyingNullable)
 5444                        {
 5445                            EmitLoadLocalVariable(il, switchValueVar);
 5446                            if (!TryEmit(caseTestValue, paramExprs, il, ref closure, setup, operandParent, param1ByRefIn
 5447                                !EmitMethodCall(il, equalityMethod))
 5448                                return false;
 5449                            il.Demit(OpCodes.Brtrue, caseBodyLabel);
 5450                            continue;
 5451                        }
 5452
 5453                        if (equalityMethod == null)
 5454                        {
 5455                            // short-circuit the comparison with the null, if the switch value has value == false the le
 5456                            if (caseTestValue is ConstantExpression r && r.Value == null)
 5457                            {
 5458                                EmitLoadLocalVariableAddress(il, switchValueVar);
 5459                                EmitMethodCall(il, switchNullableHasValueMethod);
 5460                                il.Demit(OpCodes.Brfalse, caseBodyLabel);
 5461                                continue;
 5462                            }
 5463                        }
 5464
 5465                        // Compare the switch value with the case value via Ceq or comparison method and then compare th
 5466                        EmitLoadLocalVariableAddress(il, switchValueVar);
 5467                        il.Demit(OpCodes.Ldfld, switchNullableUnsafeValueField);
 5468                        if (!TryEmit(caseTestValue, paramExprs, il, ref closure, setup, operandParent, param1ByRefIndex)
 5469                            return false;
 5470                        var caseValueVar = EmitStoreAndLoadLocalVariableAddress(il, switchValueType);
 5471                        il.Demit(OpCodes.Ldfld, switchNullableUnsafeValueField);
 5472                        if (equalityMethod == null)
 5473                            il.Demit(OpCodes.Ceq);
 5474                        else if (!EmitMethodCall(il, equalityMethod))
 5475                            return false;
 5476
 5477                        EmitLoadLocalVariableAddress(il, switchValueVar);
 5478                        EmitMethodCall(il, switchNullableHasValueMethod);
 5479                        EmitLoadLocalVariableAddress(il, caseValueVar);
 5480                        EmitMethodCall(il, switchNullableHasValueMethod);
 5481                        il.Demit(OpCodes.Ceq);
 5482
 5483                        il.Demit(OpCodes.And); // both the Nullable values and HashValue results need to be true
 5484                        il.Demit(OpCodes.Brtrue, caseBodyLabel);
 5485                    }
 5486                }
 5487
 5488                var defaultBody = expr.DefaultBody;
 5489                if (defaultBody == null)
 5490                {
 5491                    // hop over the cases bodies right to the end of switch
 5492                    il.Demit(OpCodes.Br, switchEndLabel);
 5493                }
 5494                else
 5495                {
 5496                    if (!TryEmit(defaultBody, paramExprs, il, ref closure, setup, parent))
 5497                        return false;
 5498                    // as we are at the end, no need to jump to it
 5499                    il.Demit(OpCodes.Br, switchEndLabel);
 5500                }
 5501
 5502                for (var caseIndex = 0; caseIndex < caseLabels.Length; ++caseIndex)
 5503                {
 5504                    il.DmarkLabel(caseLabels[caseIndex]);
 5505                    var cs = cases[caseIndex];
 5506                    if (!TryEmit(cs.Body, paramExprs, il, ref closure, setup, parent))
 5507                        return false;
 5508
 5509                    il.Demit(OpCodes.Br, switchEndLabel);
 5510                }
 5511
 5512                il.DmarkLabel(switchEndLabel);
 5513                return true;
 5514            }
 5515
 5516
 5517            // todo: @perf cache found method, because for some cases there many methods to search from, e.g. 157 method
 5518            private static MethodInfo FindBinaryOperandMethod(
 5519                string methodName, Type sourceType, Type leftOpType, Type rightOpType, Type resultType)
 5520            {
 5521                var methods = sourceType.GetMethods();
 5522                for (var i = 0; i < methods.Length; i++)
 5523                {
 5524                    var m = methods[i];
 5525                    if (m.IsSpecialName && m.IsStatic && m.Name == methodName && m.ReturnType == resultType)
 5526                    {
 5527                        var ps = m.GetParameters();
 5528                        if (ps.Length == 2 && ps[0].ParameterType == leftOpType && ps[1].ParameterType == rightOpType)
 5529                            return m;
 5530                    }
 5531                }
 5532                return null;
 5533            }
 5534
 5535            private static bool TryEmitComparison(
 5536                Expression left, Expression right, Type exprType, ExpressionType nodeType,
 5537#if LIGHT_EXPRESSION
 5538                IParameterProvider paramExprs,
 5539#else
 5540                IReadOnlyList<PE> paramExprs,
 5541#endif
 5542                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 5543            {
 5544                var leftType = left.Type;
 5545                var leftIsNullable = leftType.IsNullable();
 5546                var rightType = right.Type;
 5547
 5548                // If one operand is `null` then the equality comparison can be simplified to `ldnull, ceq`
 5549                var rightIsNull = IsNullContainingExpression(right);
 5550                var comparingToRightNull = rightIsNull & rightType.IsClass;
 5551
 5552                // Coalesce the right object type to the more specific left type
 5553                if (comparingToRightNull & rightType == typeof(object))
 5554                    rightType = leftType;
 5555
 5556                var leftIsNull = IsNullContainingExpression(left);
 5557                var comparingToLeftNull = leftIsNull & leftType.IsClass;
 5558                if (!comparingToRightNull && comparingToLeftNull & leftType == typeof(object))
 5559                    leftType = rightType;
 5560
 5561                var operandParent = parent & ~ParentFlags.IgnoreResult & ~ParentFlags.InstanceAccess;
 5562
 5563                // short-circuit the comparison with null on the right
 5564                var isEqualityOp = nodeType == ExpressionType.Equal | nodeType == ExpressionType.NotEqual;
 5565                if (isEqualityOp)
 5566                {
 5567                    if (leftIsNullable & rightIsNull)
 5568                    {
 5569                        if (!TryEmit(left, paramExprs, il, ref closure, setup, operandParent))
 5570                            return false;
 5571
 5572                        // See #341 `Nullable_decimal_parameter_with_decimal_constant_comparison_cases`
 5573                        if (!closure.LastEmitIsAddress && !(left is ParameterExpression p && p.IsByRef)) // Nullable typ
 5574                            EmitStoreAndLoadLocalVariableAddress(il, leftType);
 5575
 5576                        EmitMethodCall(il, leftType.GetNullableHasValueGetterMethod());
 5577                        if (nodeType == ExpressionType.Equal)
 5578                            EmitEqualToZeroOrNull(il);
 5579                        return il.EmitPopIfIgnoreResult(parent);
 5580                    }
 5581
 5582                    if (leftIsNull && rightType.IsNullable())
 5583                    {
 5584                        if (!TryEmit(right, paramExprs, il, ref closure, setup, operandParent))
 5585                            return false;
 5586
 5587                        if (!closure.LastEmitIsAddress && !(right is ParameterExpression p && p.IsByRef))
 5588                            EmitStoreAndLoadLocalVariableAddress(il, rightType);
 5589
 5590                        EmitMethodCall(il, rightType.GetNullableHasValueGetterMethod());
 5591                        if (nodeType == ExpressionType.Equal)
 5592                            EmitEqualToZeroOrNull(il);
 5593                        return il.EmitPopIfIgnoreResult(parent);
 5594                    }
 5595                }
 5596
 5597                var lVarIndex = -1;
 5598                var rightIsComplexExpression = false;
 5599                // just load the `null` later when done with the right operand, without need for go to nested TryEmit ca
 5600                // and store, load the left result for the complex expressions, see `IsComplexExpression` and #422
 5601                if (!leftIsNull)
 5602                {
 5603                    if (!TryEmit(left, paramExprs, il, ref closure, setup, operandParent))
 5604                        return false;
 5605
 5606                    // save the left result to restore it later after the complex expression, see #422
 5607                    if (rightIsComplexExpression = right.IsComplexExpression())
 5608                        lVarIndex = EmitStoreLocalVariable(il, leftType);
 5609                    else if (leftIsNullable)
 5610                    {
 5611                        lVarIndex = EmitStoreAndLoadLocalVariableAddress(il, leftType);
 5612                        il.Demit(OpCodes.Ldfld, leftType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod());
 5613                        leftType = Nullable.GetUnderlyingType(leftType);
 5614                    }
 5615                }
 5616
 5617                if (rightIsNull)
 5618                    il.Demit(OpCodes.Ldnull);
 5619                else if (!TryEmit(right, paramExprs, il, ref closure, setup, operandParent))
 5620                    return false;
 5621
 5622                if (comparingToLeftNull | comparingToRightNull ||
 5623                    (leftType != rightType && leftType.IsClass && rightType.IsClass &&
 5624                    (leftType == typeof(object) | rightType == typeof(object))))
 5625                {
 5626                    // If the operation is not Equal or NotEqual then comparison with null is not possible
 5627                    if (!isEqualityOp)
 5628                        return false;
 5629
 5630                    if (leftIsNull)
 5631                        il.Demit(OpCodes.Ldnull);
 5632                    else if (rightIsComplexExpression)
 5633                        EmitLoadLocalVariable(il, lVarIndex); // the order of comparison does not matter, because equali
 5634
 5635                    il.Demit(OpCodes.Ceq);
 5636                    if (nodeType == ExpressionType.NotEqual)
 5637                        EmitEqualToZeroOrNull(il);
 5638
 5639                    return il.EmitPopIfIgnoreResult(parent);
 5640                }
 5641
 5642                var rVarIndex = -1;
 5643                if (rightIsComplexExpression)
 5644                {
 5645                    rVarIndex = EmitStoreLocalVariable(il, rightType);
 5646                    if (!leftIsNullable)
 5647                        EmitLoadLocalVariable(il, lVarIndex);
 5648                    else
 5649                    {
 5650                        EmitLoadLocalVariableAddress(il, lVarIndex);
 5651                        il.Demit(OpCodes.Ldfld, leftType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod());
 5652                        leftType = Nullable.GetUnderlyingType(leftType);
 5653                    }
 5654
 5655                    if (!rightType.IsNullable())
 5656                        EmitLoadLocalVariable(il, rVarIndex);
 5657                    else
 5658                    {
 5659                        EmitLoadLocalVariableAddress(il, rVarIndex);
 5660                        il.Demit(OpCodes.Ldfld, rightType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod());
 5661                        rightType = Nullable.GetUnderlyingType(rightType);
 5662                    }
 5663                }
 5664                else if (leftIsNull)
 5665                {
 5666                    // here we're handling only non-nullable right, the nullable right with null left is handled above
 5667                    rVarIndex = EmitStoreLocalVariable(il, rightType);
 5668                    il.Demit(OpCodes.Ldnull);
 5669                    EmitLoadLocalVariable(il, rVarIndex);
 5670                }
 5671                else if (rightType.IsNullable())
 5672                {
 5673                    rVarIndex = EmitStoreAndLoadLocalVariableAddress(il, rightType);
 5674                    il.Demit(OpCodes.Ldfld, rightType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod());
 5675                    rightType = Nullable.GetUnderlyingType(rightType);
 5676                }
 5677
 5678                if (!leftType.IsPrimitive && !leftType.IsEnum)
 5679                {
 5680                    var methodName
 5681                        = nodeType == ExpressionType.Equal ? "op_Equality"
 5682                        : nodeType == ExpressionType.NotEqual ? "op_Inequality"
 5683                        : nodeType == ExpressionType.GreaterThan ? "op_GreaterThan"
 5684                        : nodeType == ExpressionType.GreaterThanOrEqual ? "op_GreaterThanOrEqual"
 5685                        : nodeType == ExpressionType.LessThan ? "op_LessThan"
 5686                        : nodeType == ExpressionType.LessThanOrEqual ? "op_LessThanOrEqual"
 5687                        : null;
 5688                    if (methodName == null)
 5689                        return false;
 5690
 5691                    var method = FindBinaryOperandMethod(methodName, leftType, leftType, rightType, typeof(bool));
 5692                    if (method == null & leftType != rightType)
 5693                        method = FindBinaryOperandMethod(methodName, rightType, leftType, rightType, typeof(bool));
 5694                    if (method != null)
 5695                    {
 5696                        var ok = EmitMethodCall(il, method);
 5697                        if (leftIsNullable)
 5698                            goto nullableCheck;
 5699                        return ok;
 5700                    }
 5701
 5702                    if (!isEqualityOp)
 5703                        return false; // todo: @unclear what is the alternative?
 5704
 5705                    EmitMethodCall(il, _objectEqualsMethod);
 5706                    if (nodeType == ExpressionType.NotEqual) // invert result for not equal
 5707                        EmitEqualToZeroOrNull(il);
 5708
 5709                    if (leftIsNullable)
 5710                        goto nullableCheck;
 5711
 5712                    return il.EmitPopIfIgnoreResult(parent);
 5713                }
 5714
 5715                // handle primitives comparison
 5716                switch (nodeType)
 5717                {
 5718                    case ExpressionType.Equal:
 5719                        il.Demit(OpCodes.Ceq);
 5720                        break;
 5721                    case ExpressionType.NotEqual:
 5722                        il.Demit(OpCodes.Ceq);
 5723                        EmitEqualToZeroOrNull(il);
 5724                        break;
 5725                    case ExpressionType.LessThan:
 5726                        il.Demit(OpCodes.Clt);
 5727                        break;
 5728                    case ExpressionType.GreaterThan:
 5729                        il.Demit(OpCodes.Cgt);
 5730                        break;
 5731                    case ExpressionType.GreaterThanOrEqual:
 5732                        // simplifying by using the LessThen (Clt) and comparing with negative outcome (Ceq 0)
 5733                        if (leftType.IsUnsigned() && rightType.IsUnsigned() ||
 5734                            (leftType.IsFloatingPoint() || rightType.IsFloatingPoint()))
 5735                            il.Demit(OpCodes.Clt_Un);
 5736                        else
 5737                            il.Demit(OpCodes.Clt);
 5738                        EmitEqualToZeroOrNull(il);
 5739                        break;
 5740                    case ExpressionType.LessThanOrEqual:
 5741                        // simplifying by using the GreaterThen (Cgt) and comparing with negative outcome (Ceq 0)
 5742                        if (leftType.IsUnsigned() && rightType.IsUnsigned() ||
 5743                            (leftType.IsFloatingPoint() || rightType.IsFloatingPoint()))
 5744                            il.Demit(OpCodes.Cgt_Un);
 5745                        else
 5746                            il.Demit(OpCodes.Cgt);
 5747                        EmitEqualToZeroOrNull(il);
 5748                        break;
 5749
 5750                    default:
 5751                        return false;
 5752                }
 5753
 5754            nullableCheck:
 5755                if (leftIsNullable)
 5756                {
 5757                    var leftNullableHasValueGetterMethod = left.Type.GetNullableHasValueGetterMethod(); // asking from t
 5758
 5759                    EmitLoadLocalVariableAddress(il, lVarIndex);
 5760                    EmitMethodCall(il, leftNullableHasValueGetterMethod);
 5761
 5762                    var isLiftedToNull = exprType == typeof(bool?);
 5763                    var leftHasValueVar = -1;
 5764                    if (isLiftedToNull)
 5765                        EmitStoreAndLoadLocalVariable(il, leftHasValueVar = il.GetNextLocalVarIndex(typeof(bool)));
 5766
 5767                    // ReSharper disable once AssignNullToNotNullAttribute
 5768                    EmitLoadLocalVariableAddress(il, rVarIndex);
 5769                    EmitMethodCall(il, leftNullableHasValueGetterMethod);
 5770
 5771                    var rightHasValueVar = -1;
 5772                    if (isLiftedToNull)
 5773                        EmitStoreAndLoadLocalVariable(il, rightHasValueVar = il.GetNextLocalVarIndex(typeof(bool)));
 5774
 5775                    switch (nodeType)
 5776                    {
 5777                        case ExpressionType.Equal:
 5778                            il.Demit(OpCodes.Ceq); // compare both HasValue calls
 5779                            il.Demit(OpCodes.And); // both results need to be true
 5780                            break;
 5781
 5782                        case ExpressionType.NotEqual:
 5783                            il.Demit(OpCodes.Ceq);
 5784                            EmitEqualToZeroOrNull(il);
 5785                            il.Demit(OpCodes.Or);
 5786                            break;
 5787
 5788                        case ExpressionType.LessThan:
 5789                        case ExpressionType.GreaterThan:
 5790                        case ExpressionType.LessThanOrEqual:
 5791                        case ExpressionType.GreaterThanOrEqual:
 5792                            // left.HasValue `and` right.HasValue
 5793                            il.Demit(OpCodes.And);
 5794                            // `and` the prev result of comparison operation
 5795                            il.Demit(OpCodes.And);
 5796                            break;
 5797
 5798                        default:
 5799                            return false;
 5800                    }
 5801
 5802                    if (isLiftedToNull)
 5803                    {
 5804                        var resultLabel = il.DefineLabel();
 5805                        var isNullLabel = il.DefineLabel();
 5806                        EmitLoadLocalVariable(il, leftHasValueVar);
 5807                        il.Demit(OpCodes.Brfalse, isNullLabel);
 5808                        EmitLoadLocalVariable(il, rightHasValueVar);
 5809                        il.Demit(OpCodes.Brtrue, resultLabel);
 5810                        il.DmarkLabel(isNullLabel);
 5811                        il.Demit(OpCodes.Pop);
 5812                        il.Demit(OpCodes.Ldnull);
 5813                        il.DmarkLabel(resultLabel);
 5814                    }
 5815                }
 5816
 5817                return il.EmitPopIfIgnoreResult(parent);
 5818            }
 5819
 5820            private static bool TryEmitArithmetic(Expression left, Expression right, ExpressionType nodeType, Type exprT
 5821#if LIGHT_EXPRESSION
 5822                IParameterProvider paramExprs,
 5823#else
 5824                IReadOnlyList<PE> paramExprs,
 5825#endif
 5826                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 5827            {
 5828                var flags = (parent
 5829                    & ~(ParentFlags.IgnoreResult | ParentFlags.InstanceCall |
 5830                        ParentFlags.LambdaCall | ParentFlags.ReturnByRef))
 5831                    | ParentFlags.Arithmetic;
 5832
 5833                var noNullableValueLabel = default(Label);
 5834                var leftType = left.Type;
 5835                var leftIsNullable = leftType.IsNullable();
 5836                var leftVar = -1;
 5837                var leftValueVar = -1;
 5838                if (leftIsNullable)
 5839                {
 5840                    noNullableValueLabel = il.DefineLabel();
 5841                    if (!TryEmit(left, paramExprs, il, ref closure, setup, flags | ParentFlags.InstanceCall))
 5842                        return false;
 5843
 5844                    leftVar = EmitStoreAndLoadLocalVariableAddress(il, leftType);
 5845                    EmitMethodCall(il, leftType.GetNullableHasValueGetterMethod());
 5846                    il.Demit(OpCodes.Brfalse, noNullableValueLabel);
 5847
 5848                    EmitLoadLocalVariableAddress(il, leftVar);
 5849                    il.Demit(OpCodes.Ldfld, leftType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod());
 5850                    leftValueVar = EmitStoreLocalVariable(il, Nullable.GetUnderlyingType(leftType));
 5851                }
 5852                else if (!TryEmit(left, paramExprs, il, ref closure, setup, flags))
 5853                    return false;
 5854
 5855                var rightIsNullable = false;
 5856                if (right == null) // indicates the increment/decrement operation
 5857                {
 5858                    EmitIncOrDec(il, nodeType == ExpressionType.Add);
 5859                }
 5860                else
 5861                {
 5862                    // Stores the left value for later to restore it after the complex right emit,
 5863                    // it prevents the problems in cases of right being a block, try-catch, etc.
 5864                    // see `Using_try_finally_as_arithmetic_operand_use_void_block_in_finally`
 5865                    var rightType = right.Type;
 5866                    if (leftValueVar == -1 && right.IsComplexExpression())
 5867                        leftValueVar = EmitStoreLocalVariable(il, leftType);
 5868
 5869                    var rightVar = -1;
 5870                    var rightValueVar = -1;
 5871                    rightIsNullable = rightType.IsNullable();
 5872                    if (rightIsNullable)
 5873                    {
 5874                        if (!TryEmit(right, paramExprs, il, ref closure, setup, flags | ParentFlags.InstanceCall))
 5875                            return false;
 5876
 5877                        rightVar = EmitStoreAndLoadLocalVariableAddress(il, rightType);
 5878
 5879                        EmitMethodCall(il, rightType.GetNullableHasValueGetterMethod());
 5880                        il.Demit(OpCodes.Brfalse, noNullableValueLabel);
 5881
 5882                        EmitLoadLocalVariableAddress(il, rightVar);
 5883                        il.Demit(OpCodes.Ldfld, rightType.GetNullableValueUnsafeAkaGetValueOrDefaultMethod());
 5884                        rightValueVar = EmitStoreLocalVariable(il, Nullable.GetUnderlyingType(rightType));
 5885                    }
 5886                    else if (!TryEmit(right, paramExprs, il, ref closure, setup, flags))
 5887                        return false;
 5888
 5889                    // Means that it was complex right and the result of the left operation was stored
 5890                    // and should be restored now, so the left and right go in order before the arithmetic operation
 5891                    if (leftValueVar != -1)
 5892                    {
 5893                        if (rightValueVar == -1)
 5894                            rightValueVar = EmitStoreLocalVariable(il, rightType);
 5895                        EmitLoadLocalVariable(il, leftValueVar);
 5896                        EmitLoadLocalVariable(il, rightValueVar);
 5897                    }
 5898
 5899                    if (!TryEmitArithmeticOperation(leftType, rightType, nodeType, exprType, il))
 5900                        return false;
 5901                }
 5902
 5903                if (leftIsNullable | rightIsNullable)
 5904                {
 5905                    var valueLabel = il.DefineLabel();
 5906                    il.Demit(OpCodes.Br, valueLabel);
 5907
 5908                    il.DmarkLabel(noNullableValueLabel);
 5909
 5910                    if (exprType.IsNullable())
 5911                    {
 5912                        EmitLoadLocalVariable(il, InitValueTypeVariable(il, exprType));
 5913                        var endLabel = il.DefineLabel();
 5914                        il.Demit(OpCodes.Br_S, endLabel);
 5915                        il.DmarkLabel(valueLabel);
 5916                        il.Demit(OpCodes.Newobj, exprType.GetNullableConstructor());
 5917                        il.DmarkLabel(endLabel);
 5918                    }
 5919                    else
 5920                    {
 5921                        il.Demit(OpCodes.Ldc_I4_0);
 5922                        il.DmarkLabel(valueLabel);
 5923                    }
 5924                }
 5925
 5926                il.EmitPopIfIgnoreResult(parent);
 5927                return true;
 5928            }
 5929
 5930            private static MethodInfo _stringStringConcatMethod, _stringObjectConcatMethod;
 5931            private static MethodInfo GetStringConcatMethod(Type paraType)
 5932            {
 5933                var methods = typeof(string).GetMethods();
 5934                for (var i = 0; i < methods.Length; i++)
 5935                {
 5936                    var m = methods[i];
 5937                    if (m.IsStatic && m.Name == "Concat" &&
 5938                        m.GetParameters().Length == 2 && m.GetParameters()[0].ParameterType == paraType)
 5939                        return m;
 5940                }
 5941                return null;
 5942            }
 5943
 5944            private static bool TryEmitArithmeticOperation(Type leftType, Type rightType, ExpressionType arithmeticNodeT
 5945            {
 5946                if (!exprType.IsPrimitive)
 5947                {
 5948                    if (exprType.IsNullable())
 5949                        exprType = Nullable.GetUnderlyingType(exprType);
 5950
 5951                    if (!exprType.IsPrimitive)
 5952                    {
 5953                        var opMethodName = arithmeticNodeType.GetArithmeticBinaryOperatorMethodName();
 5954                        if (opMethodName == null)
 5955                            return false; // todo: @feature should return specific error
 5956
 5957                        MethodInfo method = null;
 5958                        if (exprType != typeof(string))
 5959                        {
 5960                            // Note, that the result operation Type may be different from the operand Type,
 5961                            // e.g. `TimeSpan op_Subtraction(DateTime, DateTime)`, that mean we should look
 5962                            // for the specific method in the operand types, then in the result (expr) type.
 5963                            method = FindBinaryOperandMethod(opMethodName, leftType, leftType, rightType, exprType);
 5964                            if (method == null & leftType != rightType)
 5965                                method = FindBinaryOperandMethod(opMethodName, rightType, leftType, rightType, exprType)
 5966                            if (method == null & leftType != exprType & rightType != exprType)
 5967                                method = FindBinaryOperandMethod(opMethodName, exprType, leftType, rightType, exprType);
 5968                            // todo: @feature should return specific error
 5969                            return method != null && EmitMethodCall(il, method);
 5970                        }
 5971
 5972                        method = leftType != rightType | leftType != typeof(string)
 5973                            ? _stringObjectConcatMethod ?? (_stringObjectConcatMethod = GetStringConcatMethod(typeof(obj
 5974                            : _stringStringConcatMethod ?? (_stringStringConcatMethod = GetStringConcatMethod(typeof(str
 5975
 5976                        return method != null && EmitMethodCallOrVirtualCall(il, method);
 5977                    }
 5978                }
 5979
 5980                var opCode = arithmeticNodeType switch
 5981                {
 5982                    ExpressionType.Add => OpCodes.Add,
 5983                    ExpressionType.AddChecked => exprType.IsUnsigned() ? OpCodes.Add_Ovf_Un : OpCodes.Add_Ovf,
 5984                    ExpressionType.Subtract => OpCodes.Sub,
 5985                    ExpressionType.SubtractChecked => exprType.IsUnsigned() ? OpCodes.Sub_Ovf_Un : OpCodes.Sub_Ovf,
 5986                    ExpressionType.Multiply => OpCodes.Mul,
 5987                    ExpressionType.MultiplyChecked => exprType.IsUnsigned() ? OpCodes.Mul_Ovf_Un : OpCodes.Mul_Ovf,
 5988                    ExpressionType.Divide => OpCodes.Div,
 5989                    ExpressionType.Modulo => OpCodes.Rem,
 5990                    ExpressionType.And => OpCodes.And,
 5991                    ExpressionType.Or => OpCodes.Or,
 5992                    ExpressionType.ExclusiveOr => OpCodes.Xor,
 5993                    ExpressionType.LeftShift => OpCodes.Shl,
 5994                    ExpressionType.RightShift => exprType.IsUnsigned() ? OpCodes.Shr_Un : OpCodes.Shr,
 5995                    ExpressionType.Power => OpCodes.Call,
 5996                    _ => throw new NotSupportedException("Unsupported arithmetic operation: " + arithmeticNodeType)
 5997                };
 5998
 5999                if (opCode.Equals(OpCodes.Call))
 6000                    il.Demit(OpCodes.Call, typeof(Math).FindMethod("Pow"));
 6001                else
 6002                    il.Demit(opCode);
 6003                return true;
 6004            }
 6005
 6006            private static bool TryEmitLogicalOperator(BinaryExpression expr, ExpressionType nodeType,
 6007#if LIGHT_EXPRESSION
 6008                IParameterProvider paramExprs,
 6009#else
 6010                IReadOnlyList<PE> paramExprs,
 6011#endif
 6012                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 6013            {
 6014                if (!TryEmit(expr.Left, paramExprs, il, ref closure, setup, parent))
 6015                    return false;
 6016
 6017                var labelSkipRight = il.DefineLabel();
 6018                il.Demit(nodeType == ExpressionType.AndAlso ? OpCodes.Brfalse : OpCodes.Brtrue, labelSkipRight);
 6019
 6020                if (!TryEmit(expr.Right, paramExprs, il, ref closure, setup, parent))
 6021                    return false;
 6022
 6023                var labelDone = il.DefineLabel();
 6024                il.Demit(OpCodes.Br, labelDone);
 6025
 6026                il.DmarkLabel(labelSkipRight); // label the second branch
 6027                il.Demit(nodeType == ExpressionType.AndAlso ? OpCodes.Ldc_I4_0 : OpCodes.Ldc_I4_1);
 6028                il.DmarkLabel(labelDone);
 6029
 6030                return true;
 6031            }
 6032
 6033            private static bool IsNullContainingExpression(Expression expr) =>
 6034                expr is DefaultExpression ld && (ld.Type.IsClass || ld.Type.IsNullable()) ||
 6035                expr is ConstantExpression lc && lc.Value == null;
 6036
 6037            private static bool TryEmitConditional(
 6038                Expression testExpr, Expression ifTrueExpr, Expression ifFalseExpr,
 6039                // Type type, // todo: @wip what about the type, what if it is a void?
 6040#if LIGHT_EXPRESSION
 6041                IParameterProvider paramExprs,
 6042#else
 6043                IReadOnlyList<PE> paramExprs,
 6044#endif
 6045                ILGenerator il, ref ClosureInfo closure, CompilerFlags setup, ParentFlags parent)
 6046            {
 6047                testExpr = TryReduceCondition(testExpr);
 6048                var testNodeType = testExpr.NodeType;
 6049
 6050                // Detect a simplistic case when we can use `Brtrue` or `Brfalse`.
 6051                // We are checking the negative result to go into the `IfFalse` branch,
 6052                // because for `IfTrue` we don't need to jump and just need to proceed emitting the `IfTrue` expression
 6053                //
 6054                // The cases:
 6055                // `x == true`  => `Brfalse`
 6056                // `x != true`  => `Brtrue`
 6057                // `x == false` => `Brtrue`
 6058                // `x != false` => `Brfalse`
 6059                // `x == null`  => `Brtrue`
 6060                // `x != null`  => `Brfalse`
 6061                // `x == 0`     => `Brtrue`
 6062                // `x != 0`     => `Brfalse`
 6063
 6064                var useBrFalseOrTrue = -1; // 0 - is comparison with Zero (0, null, false), 1 - is comparison with (true
 6065                Type nullOfValueType = null;
 6066                if (testExpr is BinaryExpression tb &&
 6067                    (testNodeType == ExpressionType.Equal | testNodeType == ExpressionType.NotEqual))
 6068                {
 6069                    var testLeftExpr = tb.Left;
 6070                    var testRightExpr = tb.Right;
 6071
 6072                    Expression oppositeTestExpr = null;
 6073                    var sideConstExpr = testRightExpr as ConstantExpression ?? testLeftExpr as ConstantExpression;
 6074                    if (sideConstExpr != null)
 6075                    {
 6076                        oppositeTestExpr = sideConstExpr == testLeftExpr ? testRightExpr : testLeftExpr;
 6077                        var sideConstVal = sideConstExpr.Value;
 6078                        if (sideConstVal == null) // todo: @perf we need to optimize for the Default as well
 6079                        {
 6080                            useBrFalseOrTrue = 0;
 6081                            if (oppositeTestExpr.Type.IsNullable())
 6082                                nullOfValueType = oppositeTestExpr.Type;
 6083                        }
 6084                        else if (sideConstVal is bool boolConst)
 6085                            useBrFalseOrTrue = boolConst ? 1 : 0;
 6086                        else if (sideConstVal is int intConst && intConst == 0)
 6087                            useBrFalseOrTrue = 0; // Brtrue does not work for `1`, you need to use Beq, or similar
 6088                        else if (sideConstVal is byte bytConst && bytConst == 0)
 6089                            useBrFalseOrTrue = 0;
 6090                    }
 6091                    else
 6092                    {
 6093                        var sideDefaultExpr = testRightExpr as DefaultExpression ?? testLeftExpr as DefaultExpression;
 6094                        if (sideDefaultExpr != null)
 6095                        {
 6096                            oppositeTestExpr = sideDefaultExpr == testLeftExpr ? testRightExpr : testLeftExpr;
 6097                            var testSideType = sideDefaultExpr.Type;
 6098                            // except decimal, because its 0 is Decimal.Zero a struct and is not working with Brtrue/Brf
 6099                            if (testSideType.IsPrimitiveWithZeroDefaultExceptDecimal())
 6100                                useBrFalseOrTrue = 0;
 6101                            else if (testSideType.IsClass || testSideType.IsNullable())
 6102                            {
 6103                                useBrFalseOrTrue = 0;
 6104                                if (oppositeTestExpr.Type.IsNullable())
 6105                                    nullOfValueType = oppositeTestExpr.Type;
 6106                            }
 6107                        }
 6108                    }
 6109
 6110                    if (useBrFalseOrTrue != -1 &&
 6111                        !TryEmit(oppositeTestExpr, paramExprs, il, ref closure, setup, parent & ~ParentFlags.IgnoreResul
 6112                        return false;
 6113                }
 6114
 6115                if (useBrFalseOrTrue == -1 &&
 6116                    !TryEmit(testExpr, paramExprs, il, ref closure, setup, parent & ~ParentFlags.IgnoreResult))
 6117                    return false;
 6118
 6119                if (nullOfValueType != null)
 6120                {
 6121                    if (!closure.LastEmitIsAddress)
 6122                        EmitStoreAndLoadLocalVariableAddress(il, nullOfValueType);
 6123                    EmitMethodCall(il, nullOfValueType.GetNullableHasValueGetterMethod());
 6124                }
 6125
 6126                var labelIfFalse = il.DefineLabel();
 6127
 6128                // todo: @perf try to recognize the patterns like `b == 1` and replace Ceq, Brtrue with Beq, and respect
 6129                // for this we need to inline here the logic from the TryEmitComparison.
 6130                if ((testNodeType == ExpressionType.Equal & useBrFalseOrTrue == 0) ||
 6131                    (testNodeType == ExpressionType.NotEqual & useBrFalseOrTrue == 1))
 6132                    il.Demit(OpCodes.Brtrue, labelIfFalse);
 6133                else
 6134                    il.Demit(OpCodes.Brfalse, labelIfFalse);
 6135
 6136                if (!TryEmit(ifTrueExpr, paramExprs, il, ref closure, setup, parent))
 6137                    return false;
 6138
 6139                if (ifFalseExpr.NodeType == ExpressionType.Default && ifFalseExpr.Type == typeof(void))
 6140                    il.DmarkLabel(labelIfFalse);
 6141                else
 6142                {
 6143                    var labelDone = il.DefineLabel();
 6144                    il.Demit(OpCodes.Br, labelDone);
 6145                    il.DmarkLabel(labelIfFalse);
 6146                    if (!TryEmit(ifFalseExpr, paramExprs, il, ref closure, setup, parent))
 6147                        return false;
 6148                    il.DmarkLabel(labelDone);
 6149                }
 6150                return true;
 6151            }
 6152
 6153            private static Expression TryReduceCondition(Expression testExpr)
 6154            {
 6155                // removing Not by turning Equal -> NotEqual, NotEqual -> Equal
 6156                if (testExpr.NodeType == ExpressionType.Not)
 6157                {
 6158                    // simplify the not `==` -> `!=`, `!=` -> `==`
 6159                    var op = TryReduceCondition(((UnaryExpression)testExpr).Operand);
 6160                    var nodeType = op.NodeType;
 6161                    if (nodeType == ExpressionType.Equal) // ensures that it is a BinaryExpression
 6162                    {
 6163                        var binOp = (BinaryExpression)op;
 6164                        return NotEqual(binOp.Left, binOp.Right);
 6165                    }
 6166                    else if (nodeType == ExpressionType.NotEqual) // ensures that it is a BinaryExpression
 6167                    {
 6168                        var binOp = (BinaryExpression)op;
 6169                        return Equal(binOp.Left, binOp.Right);
 6170                    }
 6171                }
 6172                else if (testExpr is BinaryExpression b)
 6173                {
 6174                    var nodeType = b.NodeType;
 6175                    if (nodeType == ExpressionType.OrElse | nodeType == ExpressionType.Or)
 6176                    {
 6177                        if (b.Left is ConstantExpression lc && lc.Value is bool lcb)
 6178                            return lcb ? lc : TryReduceCondition(b.Right);
 6179
 6180                        if (b.Right is ConstantExpression rc && rc.Value is bool rcb && !rcb)
 6181                            return TryReduceCondition(b.Left);
 6182                    }
 6183                    else if (nodeType == ExpressionType.AndAlso | nodeType == ExpressionType.And)
 6184                    {
 6185                        if (b.Left is ConstantExpression lc && lc.Value is bool lcb)
 6186                            return !lcb ? lc : TryReduceCondition(b.Right);
 6187
 6188                        if (b.Right is ConstantExpression rc && rc.Value is bool rcb && rcb)
 6189                            return TryReduceCondition(b.Left);
 6190                    }
 6191                }
 6192
 6193                return testExpr;
 6194            }
 6195
 6196            [MethodImpl((MethodImplOptions)256)]
 6197            public static void EmitEqualToZeroOrNull(ILGenerator il)
 6198            {
 6199                il.Demit(OpCodes.Ldc_I4_0); // OpCodes.Not does not work here because it is a bitwise operation
 6200                il.Demit(OpCodes.Ceq);
 6201            }
 6202
 6203            /// Get the advantage of the optimized specialized EmitCall method
 6204            [MethodImpl((MethodImplOptions)256)]
 6205            public static bool EmitMethodCallOrVirtualCall(ILGenerator il, MethodInfo method)
 6206            {
 6207                il.Demit(method.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, method);
 6208                // todo: @feature EmitCall is specifically for the varags method and not for normal C# conventions metho
 6209                // for those you need to call Emit(OpCodes.Call|Callvirt, methodInfo).
 6210                // So for now the varargs methods are not supported yet.
 6211                return (method.CallingConvention & CallingConventions.VarArgs) == 0;
 6212            }
 6213
 6214            [MethodImpl((MethodImplOptions)256)]
 6215            public static bool EmitVirtualMethodCall(ILGenerator il, MethodInfo method)
 6216            {
 6217                il.Demit(OpCodes.Callvirt, method);
 6218                // todo: @feature EmitCall is specifically for the varags method and not for normal C# conventions metho
 6219                // for those you need to call Emit(OpCodes.Call|Callvirt, methodInfo).
 6220                // So for now the varargs methods are not supported yet.
 6221                return (method.CallingConvention & CallingConventions.VarArgs) == 0;
 6222            }
 6223
 6224            [MethodImpl((MethodImplOptions)256)]
 6225            public static bool EmitMethodCall(ILGenerator il, MethodInfo method)
 6226            {
 6227                il.Demit(OpCodes.Call, method);
 6228                // todo: @feature EmitCall is specifically for the varags method and not for normal C# conventions metho
 6229                // for those you need to call Emit(OpCodes.Call|Callvirt, methodInfo).
 6230                // So for now the varargs methods are not supported yet.
 6231                return (method.CallingConvention & CallingConventions.VarArgs) == 0;
 6232            }
 6233
 6234            /// Same as EmitMethodCall which checks the method for null first, and returns false if it is null.
 6235            [MethodImpl((MethodImplOptions)256)]
 6236            public static bool EmitMethodCallCheckForNull(ILGenerator il, MethodInfo method) =>
 6237                method != null && EmitMethodCall(il, method);
 6238
 6239            /// Same as EmitMethodCallOrVirtualCall which checks the method for null first, and returns false if it is n
 6240            [MethodImpl((MethodImplOptions)256)]
 6241            public static bool EmitMethodCallOrVirtualCallCheckForNull(ILGenerator il, MethodInfo method) =>
 6242                method != null && EmitMethodCallOrVirtualCall(il, method);
 6243
 6244            /// Efficiently emit the int constant
 6245            [MethodImpl((MethodImplOptions)256)]
 6246            public static void EmitLoadConstantInt(ILGenerator il, int i)
 6247            {
 6248                switch (i)
 6249                {
 6250                    case -1: il.Demit(OpCodes.Ldc_I4_M1); break;
 6251                    case 0: il.Demit(OpCodes.Ldc_I4_0); break;
 6252                    case 1: il.Demit(OpCodes.Ldc_I4_1); break;
 6253                    case 2: il.Demit(OpCodes.Ldc_I4_2); break;
 6254                    case 3: il.Demit(OpCodes.Ldc_I4_3); break;
 6255                    case 4: il.Demit(OpCodes.Ldc_I4_4); break;
 6256                    case 5: il.Demit(OpCodes.Ldc_I4_5); break;
 6257                    case 6: il.Demit(OpCodes.Ldc_I4_6); break;
 6258                    case 7: il.Demit(OpCodes.Ldc_I4_7); break;
 6259                    case 8: il.Demit(OpCodes.Ldc_I4_8); break;
 6260                    default:
 6261                        if (i > -129 && i < 128)
 6262                            il.Demit(OpCodes.Ldc_I4_S, (sbyte)i);
 6263                        else
 6264                            il.Demit(OpCodes.Ldc_I4, i);
 6265                        break;
 6266                }
 6267            }
 6268
 6269            [MethodImpl((MethodImplOptions)256)]
 6270            private static void EmitLoadLocalVariableAddress(ILGenerator il, int location)
 6271            {
 6272                if ((uint)location <= byte.MaxValue)
 6273                    il.Demit(OpCodes.Ldloca_S, (byte)location);
 6274                else
 6275                    il.Demit(OpCodes.Ldloca, (short)location);
 6276            }
 6277
 6278            /// <summary>Load local variable on stack</summary>
 6279            [MethodImpl((MethodImplOptions)256)]
 6280            public static bool EmitLoadLocalVariable(ILGenerator il, int location)
 6281            {
 6282                if (location == 0)
 6283                    il.Demit(OpCodes.Ldloc_0);
 6284                else if (location == 1)
 6285                    il.Demit(OpCodes.Ldloc_1);
 6286                else if (location == 2)
 6287                    il.Demit(OpCodes.Ldloc_2);
 6288                else if (location == 3)
 6289                    il.Demit(OpCodes.Ldloc_3);
 6290                else if ((uint)location <= byte.MaxValue)
 6291                    il.Demit(OpCodes.Ldloc_S, (byte)location);
 6292                else
 6293                    il.Demit(OpCodes.Ldloc, (short)location);
 6294                return true;
 6295            }
 6296
 6297            [MethodImpl((MethodImplOptions)256)]
 6298            private static bool EmitIncOrDec(ILGenerator il, bool isInc = false)
 6299            {
 6300                il.Demit(OpCodes.Ldc_I4_1);
 6301                il.Demit(isInc ? OpCodes.Add : OpCodes.Sub);
 6302                return true;
 6303            }
 6304
 6305            /// <summary>Store the variable location on stack</summary>
 6306            [MethodImpl((MethodImplOptions)256)]
 6307            public static void EmitStoreLocalVariable(ILGenerator il, int location)
 6308            {
 6309                if (location == 0)
 6310                    il.Demit(OpCodes.Stloc_0);
 6311                else if (location == 1)
 6312                    il.Demit(OpCodes.Stloc_1);
 6313                else if (location == 2)
 6314                    il.Demit(OpCodes.Stloc_2);
 6315                else if (location == 3)
 6316                    il.Demit(OpCodes.Stloc_3);
 6317                else if ((uint)location <= byte.MaxValue)
 6318                    il.Demit(OpCodes.Stloc_S, (byte)location);
 6319                else
 6320                    il.Demit(OpCodes.Stloc, (short)location);
 6321            }
 6322
 6323            /// <summary>Get and store the variable of the type on stack</summary>
 6324            [MethodImpl((MethodImplOptions)256)]
 6325            public static int EmitStoreLocalVariable(ILGenerator il, Type type)
 6326            {
 6327                var location = il.GetNextLocalVarIndex(type);
 6328                EmitStoreLocalVariable(il, location);
 6329                return location;
 6330            }
 6331
 6332            /// <summary>Stores and loads the variable</summary>
 6333            [MethodImpl((MethodImplOptions)256)]
 6334            public static void EmitStoreAndLoadLocalVariable(ILGenerator il, int location)
 6335            {
 6336                if (location == 0)
 6337                {
 6338                    il.Demit(OpCodes.Stloc_0);
 6339                    il.Demit(OpCodes.Ldloc_0);
 6340                }
 6341                else if (location == 1)
 6342                {
 6343                    il.Demit(OpCodes.Stloc_1);
 6344                    il.Demit(OpCodes.Ldloc_1);
 6345                }
 6346                else if (location == 2)
 6347                {
 6348                    il.Demit(OpCodes.Stloc_2);
 6349                    il.Demit(OpCodes.Ldloc_2);
 6350                }
 6351                else if (location == 3)
 6352                {
 6353                    il.Demit(OpCodes.Stloc_3);
 6354                    il.Demit(OpCodes.Ldloc_3);
 6355                }
 6356                else if ((uint)location <= byte.MaxValue)
 6357                {
 6358                    il.Demit(OpCodes.Stloc_S, (byte)location);
 6359                    il.Demit(OpCodes.Ldloc_S, (byte)location);
 6360                }
 6361                else
 6362                {
 6363                    il.Demit(OpCodes.Stloc, (short)location);
 6364                    il.Demit(OpCodes.Ldloc, (short)location);
 6365                }
 6366            }
 6367
 6368            /// <summary>Stores and loads the variable, and returns it</summary>
 6369            public static int EmitStoreAndLoadLocalVariable(ILGenerator il, Type t)
 6370            {
 6371                var location = il.GetNextLocalVarIndex(t);
 6372                EmitStoreAndLoadLocalVariable(il, location);
 6373                return location;
 6374            }
 6375
 6376            [MethodImpl((MethodImplOptions)256)]
 6377            private static void EmitStoreAndLoadLocalVariableAddress(ILGenerator il, int location)
 6378            {
 6379                // #if DEBUG
 6380                // var ilLengthField = typeof(ILGenerator).GetField("m_length", BindingFlags.Instance | BindingFlags.Non
 6381                // var ilStreamField = typeof(ILGenerator).GetField("m_ILStream", BindingFlags.Instance | BindingFlags.N
 6382                // var ilLength = (int)ilLengthField.GetValue(il);
 6383                // var ilStream = (byte[])ilStreamField.GetValue(il);
 6384
 6385                // var ilMaxMidStackField    = typeof(ILGenerator).GetField("m_maxMidStack", BindingFlags.Instance | Bin
 6386                // var ilMaxMidStackCurField = typeof(ILGenerator).GetField("m_maxMidStackCur", BindingFlags.Instance | 
 6387                // var ilMaxMidStack    = (int)ilMaxMidStackField.GetValue(il);
 6388                // var ilMaxMidStackCur = (int)ilMaxMidStackCurField.GetValue(il);
 6389                // #endif
 6390                if (location == 0)
 6391                {
 6392                    // todo: @perf
 6393                    // the internal code for this is
 6394                    //
 6395                    // EnsureCapacity(3);
 6396                    // InternalEmit(opcode);
 6397                    // EnsureCapacity(4);
 6398                    // InternalEmit(opcode);
 6399                    // m_ILStream[m_length++] = (byte)arg;
 6400                    //
 6401                    // which translates to ->
 6402                    //
 6403                    // if (m_length + 7 >= m_ILStream.Length)
 6404                    //     IncreaseCapacity(7);
 6405                    // // No stack change here cause 1st op decrease stack by 1 and second increase by 1
 6406                    // m_ILStream[m_length++] = (byte)OpCodes.Stloc_0.Value;
 6407                    // m_ILStream[m_length++] = (byte)OpCodes.Ldloca_S.Value;
 6408                    // m_ILStream[m_length++] = (byte)0; // we may no need it
 6409                    //
 6410                    il.Demit(OpCodes.Stloc_0);
 6411                    il.Demit(OpCodes.Ldloca_S, (byte)0);
 6412                }
 6413                else if (location == 1)
 6414                {
 6415                    // todo: @perf we may introduce the EmitOne, EmitBatchNonStackModified(OpCode store, OpCode load, by
 6416                    //
 6417                    // if (ilLength + 7 < ilStream.Length)
 6418                    // {
 6419                    //     ilStream[ilLength++] = (byte)OpCodes.Stloc_1.Value;
 6420                    //     if (ilMaxMidStackCur + 1 > ilMaxMidStack)
 6421                    //         ilMaxMidStackField.SetValue(il, ilMaxMidStackCur + 1);
 6422                    //     ilStream[ilLength++] = (byte)OpCodes.Ldloca_S.Value;
 6423                    //     ilStream[ilLength++] = (byte)1;
 6424                    //     ilLengthField.SetValue(il, ilLength);
 6425                    // }
 6426                    // else
 6427                    // {
 6428                    il.Demit(OpCodes.Stloc_1);
 6429                    il.Demit(OpCodes.Ldloca_S, (byte)1);
 6430                    // }
 6431                }
 6432                else if (location == 2)
 6433                {
 6434                    il.Demit(OpCodes.Stloc_2);
 6435                    il.Demit(OpCodes.Ldloca_S, (byte)2);
 6436                }
 6437                else if (location == 3)
 6438                {
 6439                    il.Demit(OpCodes.Stloc_3);
 6440                    il.Demit(OpCodes.Ldloca_S, (byte)3);
 6441                }
 6442                else if ((uint)location <= byte.MaxValue)
 6443                {
 6444                    il.Demit(OpCodes.Stloc_S, (byte)location);
 6445                    il.Demit(OpCodes.Ldloca_S, (byte)location);
 6446                }
 6447                else
 6448                {
 6449                    il.Demit(OpCodes.Stloc, (short)location);
 6450                    il.Demit(OpCodes.Ldloca, (short)location);
 6451                }
 6452            }
 6453
 6454            private static int EmitStoreAndLoadLocalVariableAddress(ILGenerator il, Type type)
 6455            {
 6456                var location = il.GetNextLocalVarIndex(type);
 6457                EmitStoreAndLoadLocalVariableAddress(il, location);
 6458                return location;
 6459            }
 6460
 6461            [MethodImpl((MethodImplOptions)256)]
 6462            private static void EmitLoadArg(ILGenerator il, int paramIndex)
 6463            {
 6464                if (paramIndex == 0)
 6465                    il.Demit(OpCodes.Ldarg_0);
 6466                else if (paramIndex == 1)
 6467                    il.Demit(OpCodes.Ldarg_1);
 6468                else if (paramIndex == 2)
 6469                    il.Demit(OpCodes.Ldarg_2);
 6470                else if (paramIndex == 3)
 6471                    il.Demit(OpCodes.Ldarg_3);
 6472                else if ((uint)paramIndex <= byte.MaxValue)
 6473                    il.Demit(OpCodes.Ldarg_S, (byte)paramIndex);
 6474                else
 6475                    il.Demit(OpCodes.Ldarg, (short)paramIndex);
 6476            }
 6477
 6478            [MethodImpl((MethodImplOptions)256)]
 6479            private static void EmitLoadArgAddress(ILGenerator il, int paramIndex)
 6480            {
 6481                if ((uint)paramIndex <= byte.MaxValue)
 6482                    il.Demit(OpCodes.Ldarga_S, (byte)paramIndex);
 6483                else
 6484                    il.Demit(OpCodes.Ldarga, (short)paramIndex);
 6485            }
 6486
 6487            /// <summary>Tries to interpret and emit the result IL
 6488            /// In case of exception return false, to allow FEC emit normally and throw in the invocation phase</summary
 6489            public static bool TryInterpretAndEmitResult(Expression expr, ILGenerator il, ParentFlags parent, CompilerFl
 6490            {
 6491                var type = expr.Type;
 6492                Debug.Assert(type.IsPrimitive);
 6493                if ((flags & CompilerFlags.DisableInterpreter) != 0)
 6494                    return false;
 6495
 6496                var typeCode = Type.GetTypeCode(type);
 6497                try
 6498                {
 6499                    switch (typeCode)
 6500                    {
 6501                        case TypeCode.Boolean:
 6502                            var resultBool = false;
 6503                            if (!Interpreter.TryInterpretBool(ref resultBool, expr, expr.NodeType))
 6504                                return false;
 6505                            il.Demit(resultBool ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
 6506                            break;
 6507
 6508                        case TypeCode.Int32:
 6509                            int resultInt = 0;
 6510                            if (!Interpreter.TryInterpretInt(ref resultInt, expr, expr.NodeType))
 6511                                return false;
 6512                            if ((parent & ParentFlags.IgnoreResult) == 0)
 6513                                EmitLoadConstantInt(il, resultInt);
 6514                            break;
 6515                        case TypeCode.Decimal:
 6516                            decimal resultDec = default;
 6517                            if (!Interpreter.TryInterpretDecimal(ref resultDec, expr, expr.NodeType))
 6518                                return false;
 6519                            if ((parent & ParentFlags.IgnoreResult) == 0)
 6520                                EmitDecimalConstant(resultDec, il);
 6521                            break;
 6522                        default:
 6523                            Interpreter.PValue resultVal = default;
 6524                            if (!Interpreter.TryInterpretPrimitiveValue(ref resultVal, expr, typeCode, expr.NodeType))
 6525                                return false;
 6526                            if ((parent & ParentFlags.IgnoreResult) == 0)
 6527                                switch (typeCode)
 6528                                {
 6529                                    case TypeCode.Char:
 6530                                        EmitLoadConstantInt(il, resultVal.CharValue);
 6531                                        break;
 6532                                    case TypeCode.SByte:
 6533                                        EmitLoadConstantInt(il, resultVal.SByteValue);
 6534                                        break;
 6535                                    case TypeCode.Byte:
 6536                                        EmitLoadConstantInt(il, resultVal.ByteValue);
 6537                                        break;
 6538                                    case TypeCode.Int16:
 6539                                        EmitLoadConstantInt(il, resultVal.Int16Value);
 6540                                        break;
 6541                                    case TypeCode.UInt16:
 6542                                        EmitLoadConstantInt(il, resultVal.UInt16Value);
 6543                                        break;
 6544                                    case TypeCode.Int32:
 6545                                        EmitLoadConstantInt(il, resultVal.Int32Value);
 6546                                        break;
 6547                                    case TypeCode.UInt32:
 6548                                        unchecked
 6549                                        {
 6550                                            EmitLoadConstantInt(il, (int)resultVal.UInt32Value);
 6551                                        }
 6552                                        break;
 6553                                    case TypeCode.Int64:
 6554                                        il.Demit(OpCodes.Ldc_I8, resultVal.Int64Value);
 6555                                        break;
 6556                                    case TypeCode.UInt64:
 6557                                        unchecked
 6558                                        {
 6559                                            il.Demit(OpCodes.Ldc_I8, (long)resultVal.UInt64Value);
 6560                                        }
 6561                                        break;
 6562                                    case TypeCode.Single:
 6563                                        il.Demit(OpCodes.Ldc_R4, resultVal.SingleValue);
 6564                                        break;
 6565                                    case TypeCode.Double:
 6566                                        il.Demit(OpCodes.Ldc_R8, resultVal.DoubleValue);
 6567                                        break;
 6568                                    default: Interpreter.UnreachableCase(typeCode); break;
 6569                                }
 6570                            break;
 6571                    }
 6572                    return true;
 6573                }
 6574                catch
 6575                {
 6576                    // ignore exception and return the false and rethrow the exception in the invocation time
 6577                    return false;
 6578                }
 6579            }
 6580        }
 6581
 6582        /// <summary>Interpreter</summary>
 6583        internal static class Interpreter
 6584        {
 6585            /// <summary>Always returns true</summary>
 6586            public static readonly Func<bool> TrueFunc = static () => true;
 6587            /// <summary>Always returns false</summary>
 6588            public static readonly Func<bool> FalseFunc = static () => false;
 6589
 6590            /// <summary>Return value should be ignored</summary>
 6591            [MethodImpl(MethodImplOptions.NoInlining)]
 6592            internal static void UnreachableCase<T>(T @case,
 6593                [CallerMemberName] string caller = "", [CallerLineNumber] int line = -1)
 6594            {
 6595#if INTERPRETATION_DIAGNOSTICS
 6596                Console.WriteLine($"Unreachable switch case detected `{@case}` at `{caller}`:{line}");
 6597                Debugger.Break();
 6598#endif
 6599                throw new InvalidCastException($"Unreachable switch case detected `{@case}` at `{caller}`:{line}");
 6600            }
 6601
 6602            /// <summary>Return value should be ignored</summary>
 6603            [MethodImpl(MethodImplOptions.NoInlining)]
 6604            private static R UnreachableCase<T, R>(T @case, R result,
 6605                [CallerMemberName] string caller = "", [CallerLineNumber] int line = -1)
 6606            {
 6607#if INTERPRETATION_DIAGNOSTICS
 6608                Console.WriteLine($"Unreachable switch case detected `{@case}` at `{caller}`:{line}");
 6609                Debugger.Break();
 6610#endif
 6611                throw new InvalidCastException($"Unreachable switch case detected `{@case}` at `{caller}`:{line}");
 6612            }
 6613
 6614            /// <summary>Operation accepting IComparable inputs and producing bool output</summary>
 6615            [MethodImpl(MethodImplOptions.AggressiveInlining)]
 6616            public static bool IsComparison(ExpressionType nodeType) =>
 6617                nodeType == ExpressionType.Equal |
 6618                nodeType == ExpressionType.NotEqual |
 6619                nodeType == ExpressionType.GreaterThan |
 6620                nodeType == ExpressionType.GreaterThanOrEqual |
 6621                nodeType == ExpressionType.LessThan |
 6622                nodeType == ExpressionType.LessThanOrEqual;
 6623
 6624            /// <summary>Operation accepting the same primitive type inputs (or of the coalescing types) and producing t
 6625            [MethodImpl(MethodImplOptions.AggressiveInlining)]
 6626            public static bool IsArithmeticBinary(ExpressionType nodeType) =>
 6627                nodeType == ExpressionType.Add |
 6628                nodeType == ExpressionType.Subtract |
 6629                nodeType == ExpressionType.Multiply |
 6630                nodeType == ExpressionType.Divide |
 6631                nodeType == ExpressionType.Modulo |
 6632                nodeType == ExpressionType.Power |
 6633                nodeType == ExpressionType.LeftShift |
 6634                nodeType == ExpressionType.RightShift |
 6635                nodeType == ExpressionType.And |
 6636                nodeType == ExpressionType.Or |
 6637                nodeType == ExpressionType.ExclusiveOr;
 6638
 6639            [MethodImpl(MethodImplOptions.AggressiveInlining)]
 6640            internal static void NegatePrimitiveValue(ref PValue value, TypeCode code)
 6641            {
 6642                switch (code)
 6643                {
 6644                    case TypeCode.Char: value.CharValue = (char)-value.CharValue; break;
 6645                    case TypeCode.SByte: value.SByteValue = (sbyte)-value.SByteValue; break;
 6646                    case TypeCode.Byte: value.Int16Value = (short)-value.ByteValue; break;
 6647                    case TypeCode.Int16: value.Int16Value = (short)-value.Int16Value; break;
 6648                    case TypeCode.UInt16: value.Int32Value = (int)-value.UInt16Value; break;
 6649                    case TypeCode.Int32: value.Int32Value = -value.Int32Value; break;
 6650                    // Negate can not be applied to the UInt32
 6651                    case TypeCode.UInt32: UnreachableCase(code); break;
 6652                    case TypeCode.Single: value.SingleValue = -value.SingleValue; break;
 6653                    case TypeCode.Double: value.DoubleValue = -value.DoubleValue; break;
 6654                    default: UnreachableCase(code); break;
 6655                }
 6656            }
 6657
 6658            internal static void ConvertPrimitiveValueFromTo(ref PValue value, TypeCode fromCode, TypeCode toCode)
 6659            {
 6660                switch (toCode)
 6661                {
 6662                    case TypeCode.SByte:
 6663                        switch (fromCode)
 6664                        {
 6665                            case TypeCode.Char: break;
 6666                            case TypeCode.SByte: break;
 6667                            case TypeCode.Byte: value.SByteValue = (sbyte)value.ByteValue; break;
 6668                            case TypeCode.Int16: value.SByteValue = (sbyte)value.Int16Value; break;
 6669                            case TypeCode.UInt16: value.SByteValue = (sbyte)value.UInt16Value; break;
 6670                            case TypeCode.Int32: value.SByteValue = (sbyte)value.Int32Value; break;
 6671                            case TypeCode.UInt32: value.SByteValue = (sbyte)value.UInt32Value; break;
 6672                            case TypeCode.Int64: value.SByteValue = (sbyte)value.Int64Value; break;
 6673                            case TypeCode.UInt64: value.SByteValue = (sbyte)value.UInt64Value; break;
 6674                            case TypeCode.Single: value.SByteValue = (sbyte)value.SingleValue; break;
 6675                            case TypeCode.Double: value.SByteValue = (sbyte)value.DoubleValue; break;
 6676                            default: UnreachableCase(fromCode); break;
 6677                        }
 6678                        break;
 6679                    case TypeCode.Byte:
 6680                        switch (fromCode)
 6681                        {
 6682                            case TypeCode.Char: value.ByteValue = (byte)value.CharValue; break;
 6683                            case TypeCode.SByte: value.ByteValue = (byte)value.SByteValue; break;
 6684                            case TypeCode.Byte: break;
 6685                            case TypeCode.Int16: value.ByteValue = (byte)value.Int16Value; break;
 6686                            case TypeCode.UInt16: value.ByteValue = (byte)value.UInt16Value; break;
 6687                            case TypeCode.Int32: value.ByteValue = (byte)value.Int32Value; break;
 6688                            case TypeCode.UInt32: value.ByteValue = (byte)value.UInt32Value; break;
 6689                            case TypeCode.Int64: value.ByteValue = (byte)value.Int64Value; break;
 6690                            case TypeCode.UInt64: value.ByteValue = (byte)value.UInt64Value; break;
 6691                            case TypeCode.Single: value.ByteValue = (byte)value.SingleValue; break;
 6692                            case TypeCode.Double: value.ByteValue = (byte)value.DoubleValue; break;
 6693                            default: UnreachableCase(fromCode); break;
 6694                        }
 6695                        break;
 6696                    case TypeCode.Int16:
 6697                        switch (fromCode)
 6698                        {
 6699                            case TypeCode.Char: value.Int16Value = (short)value.CharValue; break;
 6700                            case TypeCode.SByte: value.Int16Value = (short)value.SByteValue; break;
 6701                            case TypeCode.Byte: value.Int16Value = (short)value.ByteValue; break;
 6702                            case TypeCode.Int16: break;
 6703                            case TypeCode.UInt16: value.Int16Value = (short)value.UInt16Value; break;
 6704                            case TypeCode.Int32: value.Int16Value = (short)value.Int32Value; break;
 6705                            case TypeCode.UInt32: value.Int16Value = (short)value.UInt32Value; break;
 6706                            case TypeCode.Int64: value.Int16Value = (short)value.Int64Value; break;
 6707                            case TypeCode.UInt64: value.Int16Value = (short)value.UInt64Value; break;
 6708                            case TypeCode.Single: value.Int16Value = (short)value.SingleValue; break;
 6709                            case TypeCode.Double: value.Int16Value = (short)value.DoubleValue; break;
 6710                            default: UnreachableCase(fromCode); break;
 6711                        }
 6712                        break;
 6713                    case TypeCode.UInt16:
 6714                        switch (fromCode)
 6715                        {
 6716                            case TypeCode.Char: value.UInt16Value = (ushort)value.CharValue; break;
 6717                            case TypeCode.SByte: value.UInt16Value = (ushort)value.SByteValue; break;
 6718                            case TypeCode.Byte: value.UInt16Value = (ushort)value.ByteValue; break;
 6719                            case TypeCode.Int16: value.UInt16Value = (ushort)value.Int16Value; break;
 6720                            case TypeCode.UInt16: break;
 6721                            case TypeCode.Int32: value.UInt16Value = (ushort)value.Int32Value; break;
 6722                            case TypeCode.UInt32: value.UInt16Value = (ushort)value.UInt32Value; break;
 6723                            case TypeCode.Int64: value.UInt16Value = (ushort)value.Int64Value; break;
 6724                            case TypeCode.UInt64: value.UInt16Value = (ushort)value.UInt64Value; break;
 6725                            case TypeCode.Single: value.UInt16Value = (ushort)value.SingleValue; break;
 6726                            case TypeCode.Double: value.UInt16Value = (ushort)value.DoubleValue; break;
 6727                            default: UnreachableCase(fromCode); break;
 6728                        }
 6729                        break;
 6730                    case TypeCode.Int32:
 6731                        switch (fromCode)
 6732                        {
 6733                            case TypeCode.Char: value.Int32Value = (int)value.CharValue; break;
 6734                            case TypeCode.SByte: value.Int32Value = (int)value.SByteValue; break;
 6735                            case TypeCode.Byte: value.Int32Value = (int)value.ByteValue; break;
 6736                            case TypeCode.Int16: value.Int32Value = (int)value.Int16Value; break;
 6737                            case TypeCode.UInt16: value.Int32Value = (int)value.UInt16Value; break;
 6738                            case TypeCode.Int32: break;
 6739                            case TypeCode.UInt32: value.Int32Value = (int)value.UInt32Value; break;
 6740                            case TypeCode.Int64: value.Int32Value = (int)value.Int64Value; break;
 6741                            case TypeCode.UInt64: value.Int32Value = (int)value.UInt64Value; break;
 6742                            case TypeCode.Single: value.Int32Value = (int)value.SingleValue; break;
 6743                            case TypeCode.Double: value.Int32Value = (int)value.DoubleValue; break;
 6744                            default: UnreachableCase(fromCode); break;
 6745                        }
 6746                        break;
 6747                    case TypeCode.UInt32:
 6748                        switch (fromCode)
 6749                        {
 6750                            case TypeCode.Char: value.UInt32Value = (uint)value.CharValue; break;
 6751                            case TypeCode.SByte: value.UInt32Value = (uint)value.SByteValue; break;
 6752                            case TypeCode.Byte: value.UInt32Value = (uint)value.ByteValue; break;
 6753                            case TypeCode.Int16: value.UInt32Value = (uint)value.Int16Value; break;
 6754                            case TypeCode.UInt16: value.UInt32Value = (uint)value.UInt16Value; break;
 6755                            case TypeCode.Int32: value.UInt32Value = (uint)value.Int32Value; break;
 6756                            case TypeCode.UInt32: break;
 6757                            case TypeCode.Int64: value.UInt32Value = (uint)value.Int64Value; break;
 6758                            case TypeCode.UInt64: value.UInt32Value = (uint)value.UInt64Value; break;
 6759                            case TypeCode.Single: value.UInt32Value = (uint)value.SingleValue; break;
 6760                            case TypeCode.Double: value.UInt32Value = (uint)value.DoubleValue; break;
 6761                            default: UnreachableCase(fromCode); break;
 6762                        }
 6763                        break;
 6764                    case TypeCode.Int64:
 6765                        switch (fromCode)
 6766                        {
 6767                            case TypeCode.Char: value.Int64Value = (long)value.CharValue; break;
 6768                            case TypeCode.SByte: value.Int64Value = (long)value.SByteValue; break;
 6769                            case TypeCode.Byte: value.Int64Value = (long)value.ByteValue; break;
 6770                            case TypeCode.Int16: value.Int64Value = (long)value.Int16Value; break;
 6771                            case TypeCode.UInt16: value.Int64Value = (long)value.UInt16Value; break;
 6772                            case TypeCode.Int32: value.Int64Value = (long)value.Int32Value; break;
 6773                            case TypeCode.UInt32: value.Int64Value = (long)value.UInt32Value; break;
 6774                            case TypeCode.Int64: break;
 6775                            case TypeCode.UInt64: value.Int64Value = (long)value.UInt64Value; break;
 6776                            case TypeCode.Single: value.Int64Value = (long)value.SingleValue; break;
 6777                            case TypeCode.Double: value.Int64Value = (long)value.DoubleValue; break;
 6778                            default: UnreachableCase(fromCode); break;
 6779                        }
 6780                        break;
 6781                    case TypeCode.UInt64:
 6782                        switch (fromCode)
 6783                        {
 6784                            case TypeCode.Char: value.UInt64Value = (ulong)value.CharValue; break;
 6785                            case TypeCode.SByte: value.UInt64Value = (ulong)value.SByteValue; break;
 6786                            case TypeCode.Byte: value.UInt64Value = (ulong)value.ByteValue; break;
 6787                            case TypeCode.Int16: value.UInt64Value = (ulong)value.Int16Value; break;
 6788                            case TypeCode.UInt16: value.UInt64Value = (ulong)value.UInt16Value; break;
 6789                            case TypeCode.Int32: value.UInt64Value = (ulong)value.Int32Value; break;
 6790                            case TypeCode.UInt32: value.UInt64Value = (ulong)value.UInt32Value; break;
 6791                            case TypeCode.Int64: value.UInt64Value = (ulong)value.Int64Value; break;
 6792                            case TypeCode.UInt64: break;
 6793                            case TypeCode.Single: value.UInt64Value = (ulong)value.SingleValue; break;
 6794                            case TypeCode.Double: value.UInt64Value = (ulong)value.DoubleValue; break;
 6795                            default: UnreachableCase(fromCode); break;
 6796                        }
 6797                        break;
 6798                    case TypeCode.Single:
 6799                        switch (fromCode)
 6800                        {
 6801                            case TypeCode.Char: value.SingleValue = (float)value.CharValue; break;
 6802                            case TypeCode.SByte: value.SingleValue = (float)value.SByteValue; break;
 6803                            case TypeCode.Byte: value.SingleValue = (float)value.ByteValue; break;
 6804                            case TypeCode.Int16: value.SingleValue = (float)value.Int16Value; break;
 6805                            case TypeCode.UInt16: value.SingleValue = (float)value.UInt16Value; break;
 6806                            case TypeCode.Int32: value.SingleValue = (float)value.Int32Value; break;
 6807                            case TypeCode.UInt32: value.SingleValue = (float)value.UInt32Value; break;
 6808                            case TypeCode.Int64: value.SingleValue = (float)value.Int64Value; break;
 6809                            case TypeCode.UInt64: value.SingleValue = (float)value.UInt64Value; break;
 6810                            case TypeCode.Single: break;
 6811                            case TypeCode.Double: value.SingleValue = (float)value.DoubleValue; break;
 6812                            default: UnreachableCase(fromCode); break;
 6813                        }
 6814                        break;
 6815                    case TypeCode.Double:
 6816                        switch (fromCode)
 6817                        {
 6818                            case TypeCode.Char: value.DoubleValue = (double)value.CharValue; break;
 6819                            case TypeCode.SByte: value.DoubleValue = (double)value.SByteValue; break;
 6820                            case TypeCode.Byte: value.DoubleValue = (double)value.ByteValue; break;
 6821                            case TypeCode.Int16: value.DoubleValue = (double)value.Int16Value; break;
 6822                            case TypeCode.UInt16: value.DoubleValue = (double)value.UInt16Value; break;
 6823                            case TypeCode.Int32: value.DoubleValue = (double)value.Int32Value; break;
 6824                            case TypeCode.UInt32: value.DoubleValue = (double)value.UInt32Value; break;
 6825                            case TypeCode.Int64: value.DoubleValue = (double)value.Int64Value; break;
 6826                            case TypeCode.UInt64: value.DoubleValue = (double)value.UInt64Value; break;
 6827                            case TypeCode.Single: value.DoubleValue = (double)value.SingleValue; break;
 6828                            case TypeCode.Double: break;
 6829                            default: UnreachableCase(fromCode); break;
 6830                        }
 6831                        break;
 6832                }
 6833            }
 6834
 6835            [DebuggerDisplay("{Code}")]
 6836            [StructLayout(LayoutKind.Explicit)]
 6837            internal struct PValue
 6838            {
 6839                [FieldOffset(0)]
 6840                public char CharValue;
 6841                [FieldOffset(0)]
 6842                public sbyte SByteValue;
 6843                [FieldOffset(0)]
 6844                public byte ByteValue;
 6845                [FieldOffset(0)]
 6846                public short Int16Value;
 6847                [FieldOffset(0)]
 6848                public ushort UInt16Value;
 6849                [FieldOffset(0)]
 6850                public int Int32Value;
 6851                [FieldOffset(0)]
 6852                public uint UInt32Value;
 6853                [FieldOffset(0)]
 6854                public long Int64Value;
 6855                [FieldOffset(0)]
 6856                public ulong UInt64Value;
 6857                [FieldOffset(0)]
 6858                public float SingleValue;
 6859                [FieldOffset(0)]
 6860                public double DoubleValue;
 6861                public PValue(char value) => CharValue = value;
 6862                public PValue(sbyte value) => SByteValue = value;
 6863                public PValue(byte value) => ByteValue = value;
 6864                public PValue(short value) => Int16Value = value;
 6865                public PValue(ushort value) => UInt16Value = value;
 6866                public PValue(int value) => Int32Value = value;
 6867                public PValue(uint value) => UInt32Value = value;
 6868                public PValue(long value) => Int64Value = value;
 6869                public PValue(ulong value) => UInt64Value = value;
 6870                public PValue(float value) => SingleValue = value;
 6871                public PValue(double value) => DoubleValue = value;
 6872            }
 6873
 6874            [MethodImpl(MethodImplOptions.AggressiveInlining)]
 6875            internal static bool TryUnboxToPrimitiveValue(ref PValue value, object boxedValue, TypeCode code)
 6876            {
 6877                switch (code)
 6878                {
 6879                    case TypeCode.Char: value.CharValue = (char)boxedValue; break;
 6880                    case TypeCode.SByte: value.SByteValue = (sbyte)boxedValue; break;
 6881                    case TypeCode.Byte: value.ByteValue = (byte)boxedValue; break;
 6882                    case TypeCode.Int16: value.Int16Value = (short)boxedValue; break;
 6883                    case TypeCode.UInt16: value.UInt16Value = (ushort)boxedValue; break;
 6884                    case TypeCode.Int32: value.Int32Value = (int)boxedValue; break;
 6885                    case TypeCode.UInt32: value.UInt32Value = (uint)boxedValue; break;
 6886                    case TypeCode.Int64: value.Int64Value = (long)boxedValue; break;
 6887                    case TypeCode.UInt64: value.UInt64Value = (ulong)boxedValue; break;
 6888                    case TypeCode.Single: value.SingleValue = (float)boxedValue; break;
 6889                    case TypeCode.Double: value.DoubleValue = (double)boxedValue; break;
 6890                    default: return false;
 6891                }
 6892                return true;
 6893            }
 6894
 6895            // todo: @perf think how to avoid this boxing thing altogether, maybe do not expose it at all to force clien
 6896            [MethodImpl(MethodImplOptions.AggressiveInlining)]
 6897            internal static object BoxPrimitiveValue(ref PValue value, TypeCode code) => code switch
 6898            {
 6899                TypeCode.Char => value.CharValue,
 6900                TypeCode.SByte => value.SByteValue,
 6901                TypeCode.Byte => value.ByteValue,
 6902                TypeCode.Int16 => value.Int16Value,
 6903                TypeCode.UInt16 => value.UInt16Value,
 6904                TypeCode.Int32 => value.Int32Value,
 6905                TypeCode.UInt32 => value.UInt32Value,
 6906                TypeCode.Int64 => value.Int64Value,
 6907                TypeCode.UInt64 => value.UInt64Value,
 6908                TypeCode.Single => value.SingleValue,
 6909                TypeCode.Double => value.DoubleValue,
 6910                _ => UnreachableCase(code, (object)null)
 6911            };
 6912
 6913            internal static bool ComparePrimitiveValues(ref PValue left, ref PValue right, TypeCode code, ExpressionType
 6914            {
 6915                switch (nodeType)
 6916                {
 6917                    case ExpressionType.GreaterThan:
 6918                        return code switch
 6919                        {
 6920                            TypeCode.Char => left.CharValue > right.CharValue,
 6921                            TypeCode.SByte => left.SByteValue > right.SByteValue,
 6922                            TypeCode.Byte => left.ByteValue > right.ByteValue,
 6923                            TypeCode.Int16 => left.Int16Value > right.Int16Value,
 6924                            TypeCode.UInt16 => left.UInt16Value > right.UInt16Value,
 6925                            TypeCode.Int32 => left.Int32Value > right.Int32Value,
 6926                            TypeCode.UInt32 => left.UInt32Value > right.UInt32Value,
 6927                            TypeCode.Int64 => left.Int64Value > right.Int64Value,
 6928                            TypeCode.UInt64 => left.UInt64Value > right.UInt64Value,
 6929                            TypeCode.Single => left.SingleValue > right.SingleValue,
 6930                            TypeCode.Double => left.DoubleValue > right.DoubleValue,
 6931                            _ => UnreachableCase(code, false)
 6932                        };
 6933                    case ExpressionType.GreaterThanOrEqual:
 6934                        return code switch
 6935                        {
 6936                            TypeCode.Char => left.CharValue >= right.CharValue,
 6937                            TypeCode.SByte => left.SByteValue >= right.SByteValue,
 6938                            TypeCode.Byte => left.ByteValue >= right.ByteValue,
 6939                            TypeCode.Int16 => left.Int16Value >= right.Int16Value,
 6940                            TypeCode.UInt16 => left.UInt16Value >= right.UInt16Value,
 6941                            TypeCode.Int32 => left.Int32Value >= right.Int32Value,
 6942                            TypeCode.UInt32 => left.UInt32Value >= right.UInt32Value,
 6943                            TypeCode.Int64 => left.Int64Value >= right.Int64Value,
 6944                            TypeCode.UInt64 => left.UInt64Value >= right.UInt64Value,
 6945                            TypeCode.Single => left.SingleValue >= right.SingleValue,
 6946                            TypeCode.Double => left.DoubleValue >= right.DoubleValue,
 6947                            _ => UnreachableCase(code, false)
 6948                        };
 6949                    case ExpressionType.LessThan:
 6950                        return code switch
 6951                        {
 6952                            TypeCode.Char => left.CharValue < right.CharValue,
 6953                            TypeCode.SByte => left.SByteValue < right.SByteValue,
 6954                            TypeCode.Byte => left.ByteValue < right.ByteValue,
 6955                            TypeCode.Int16 => left.Int16Value < right.Int16Value,
 6956                            TypeCode.UInt16 => left.UInt16Value < right.UInt16Value,
 6957                            TypeCode.Int32 => left.Int32Value < right.Int32Value,
 6958                            TypeCode.UInt32 => left.UInt32Value < right.UInt32Value,
 6959                            TypeCode.Int64 => left.Int64Value < right.Int64Value,
 6960                            TypeCode.UInt64 => left.UInt64Value < right.UInt64Value,
 6961                            TypeCode.Single => left.SingleValue < right.SingleValue,
 6962                            TypeCode.Double => left.DoubleValue < right.DoubleValue,
 6963                            _ => UnreachableCase(code, false)
 6964                        };
 6965                    case ExpressionType.LessThanOrEqual:
 6966                        return code switch
 6967                        {
 6968                            TypeCode.Char => left.CharValue <= right.CharValue,
 6969                            TypeCode.SByte => left.SByteValue <= right.SByteValue,
 6970                            TypeCode.Byte => left.ByteValue <= right.ByteValue,
 6971                            TypeCode.Int16 => left.Int16Value <= right.Int16Value,
 6972                            TypeCode.UInt16 => left.UInt16Value <= right.UInt16Value,
 6973                            TypeCode.Int32 => left.Int32Value <= right.Int32Value,
 6974                            TypeCode.UInt32 => left.UInt32Value <= right.UInt32Value,
 6975                            TypeCode.Int64 => left.Int64Value <= right.Int64Value,
 6976                            TypeCode.UInt64 => left.UInt64Value <= right.UInt64Value,
 6977                            TypeCode.Single => left.SingleValue <= right.SingleValue,
 6978                            TypeCode.Double => left.DoubleValue <= right.DoubleValue,
 6979                            _ => UnreachableCase(code, false)
 6980                        };
 6981                    default: return UnreachableCase(nodeType, false);
 6982                }
 6983            }
 6984
 6985            /// <summary>Puts the result to the `left` para meter</summary>
 6986            internal static void DoArithmeticForPrimitiveValues(ref PValue left, ref PValue right, TypeCode code, Expres
 6987            {
 6988                switch (nodeType)
 6989                {
 6990                    case ExpressionType.Add:
 6991                        switch (code)
 6992                        {
 6993                            case TypeCode.Char: left.CharValue += right.CharValue; break;
 6994                            // System Expression does not define the Add for sbyte and byte, but let's keep it here beca
 6995                            case TypeCode.SByte: left.SByteValue += right.SByteValue; break;
 6996                            case TypeCode.Byte: left.ByteValue += right.ByteValue; break;
 6997                            // the rest
 6998                            case TypeCode.Int16: left.Int16Value += right.Int16Value; break;
 6999                            case TypeCode.UInt16: left.UInt16Value += right.UInt16Value; break;
 7000                            case TypeCode.Int32: left.Int32Value += right.Int32Value; break;
 7001                            case TypeCode.UInt32: left.UInt32Value += right.UInt32Value; break;
 7002                            case TypeCode.Int64: left.Int64Value += right.Int64Value; break;
 7003                            case TypeCode.UInt64: left.UInt64Value += right.UInt64Value; break;
 7004                            case TypeCode.Single: left.SingleValue += right.SingleValue; break;
 7005                            case TypeCode.Double: left.DoubleValue += right.DoubleValue; break;
 7006                            default: UnreachableCase(code); break;
 7007                        }
 7008                        break;
 7009                    case ExpressionType.Subtract:
 7010                        switch (code)
 7011                        {
 7012                            case TypeCode.Char: left.CharValue -= right.CharValue; break;
 7013                            case TypeCode.SByte: left.SByteValue -= right.SByteValue; break;
 7014                            case TypeCode.Byte: left.ByteValue -= right.ByteValue; break;
 7015                            case TypeCode.Int16: left.Int16Value -= right.Int16Value; break;
 7016                            case TypeCode.UInt16: left.UInt16Value -= right.UInt16Value; break;
 7017                            case TypeCode.Int32: left.Int32Value -= right.Int32Value; break;
 7018                            case TypeCode.UInt32: left.UInt32Value -= right.UInt32Value; break;
 7019                            case TypeCode.Int64: left.Int64Value -= right.Int64Value; break;
 7020                            case TypeCode.UInt64: left.UInt64Value -= right.UInt64Value; break;
 7021                            case TypeCode.Single: left.SingleValue -= right.SingleValue; break;
 7022                            case TypeCode.Double: left.DoubleValue -= right.DoubleValue; break;
 7023                            default: UnreachableCase(code); break;
 7024                        }
 7025                        break;
 7026                    case ExpressionType.Multiply:
 7027                        switch (code)
 7028                        {
 7029                            case TypeCode.Char: left.CharValue *= right.CharValue; break;
 7030                            case TypeCode.SByte: left.SByteValue *= right.SByteValue; break;
 7031                            case TypeCode.Byte: left.ByteValue *= right.ByteValue; break;
 7032                            case TypeCode.Int16: left.Int16Value *= right.Int16Value; break;
 7033                            case TypeCode.UInt16: left.UInt16Value *= right.UInt16Value; break;
 7034                            case TypeCode.Int32: left.Int32Value *= right.Int32Value; break;
 7035                            case TypeCode.UInt32: left.UInt32Value *= right.UInt32Value; break;
 7036                            case TypeCode.Int64: left.Int64Value *= right.Int64Value; break;
 7037                            case TypeCode.UInt64: left.UInt64Value *= right.UInt64Value; break;
 7038                            case TypeCode.Single: left.SingleValue *= right.SingleValue; break;
 7039                            case TypeCode.Double: left.DoubleValue *= right.DoubleValue; break;
 7040                            default: UnreachableCase(code); break;
 7041                        }
 7042                        break;
 7043                    case ExpressionType.Divide:
 7044                        switch (code)
 7045                        {
 7046                            case TypeCode.Char: left.CharValue /= right.CharValue; break;
 7047                            case TypeCode.SByte: left.SByteValue /= right.SByteValue; break;
 7048                            case TypeCode.Byte: left.ByteValue /= right.ByteValue; break;
 7049                            case TypeCode.Int16: left.Int16Value /= right.Int16Value; break;
 7050                            case TypeCode.UInt16: left.UInt16Value /= right.UInt16Value; break;
 7051                            case TypeCode.Int32: left.Int32Value /= right.Int32Value; break;
 7052                            case TypeCode.UInt32: left.UInt32Value /= right.UInt32Value; break;
 7053                            case TypeCode.Int64: left.Int64Value /= right.Int64Value; break;
 7054                            case TypeCode.UInt64: left.UInt64Value /= right.UInt64Value; break;
 7055                            case TypeCode.Single: left.SingleValue /= right.SingleValue; break;
 7056                            case TypeCode.Double: left.DoubleValue /= right.DoubleValue; break;
 7057                            default: UnreachableCase(code); break;
 7058                        }
 7059                        break;
 7060                    case ExpressionType.Modulo:
 7061                        switch (code)
 7062                        {
 7063                            case TypeCode.Char: left.CharValue %= right.CharValue; break;
 7064                            case TypeCode.SByte: left.SByteValue %= right.SByteValue; break;
 7065                            case TypeCode.Byte: left.ByteValue %= right.ByteValue; break;
 7066                            case TypeCode.Int16: left.Int16Value %= right.Int16Value; break;
 7067                            case TypeCode.UInt16: left.UInt16Value %= right.UInt16Value; break;
 7068                            case TypeCode.Int32: left.Int32Value %= right.Int32Value; break;
 7069                            case TypeCode.UInt32: left.UInt32Value %= right.UInt32Value; break;
 7070                            case TypeCode.Int64: left.Int64Value %= right.Int64Value; break;
 7071                            case TypeCode.UInt64: left.UInt64Value %= right.UInt64Value; break;
 7072                            case TypeCode.Single: left.SingleValue %= right.SingleValue; break;
 7073                            case TypeCode.Double: left.DoubleValue %= right.DoubleValue; break;
 7074                            default: UnreachableCase(code); break;
 7075                        }
 7076                        break;
 7077                    case ExpressionType.And:
 7078                        switch (code)
 7079                        {
 7080                            case TypeCode.Char: left.CharValue &= right.CharValue; break;
 7081                            case TypeCode.SByte: left.SByteValue &= right.SByteValue; break;
 7082                            case TypeCode.Byte: left.ByteValue &= right.ByteValue; break;
 7083                            case TypeCode.Int16: left.Int16Value &= right.Int16Value; break;
 7084                            case TypeCode.UInt16: left.UInt16Value &= right.UInt16Value; break;
 7085                            case TypeCode.Int32: left.Int32Value &= right.Int32Value; break;
 7086                            case TypeCode.UInt32: left.UInt32Value &= right.UInt32Value; break;
 7087                            case TypeCode.Int64: left.Int64Value &= right.Int64Value; break;
 7088                            case TypeCode.UInt64: left.UInt64Value &= right.UInt64Value; break;
 7089                            default: UnreachableCase(code); break;
 7090                        }
 7091                        break;
 7092                    case ExpressionType.Or:
 7093                        switch (code)
 7094                        {
 7095                            case TypeCode.Char: left.CharValue |= right.CharValue; break;
 7096                            case TypeCode.SByte: left.SByteValue |= right.SByteValue; break;
 7097                            case TypeCode.Byte: left.ByteValue |= right.ByteValue; break;
 7098                            case TypeCode.Int16: left.Int16Value |= right.Int16Value; break;
 7099                            case TypeCode.UInt16: left.UInt16Value |= right.UInt16Value; break;
 7100                            case TypeCode.Int32: left.Int32Value |= right.Int32Value; break;
 7101                            case TypeCode.UInt32: left.UInt32Value |= right.UInt32Value; break;
 7102                            case TypeCode.Int64: left.Int64Value |= right.Int64Value; break;
 7103                            case TypeCode.UInt64: left.UInt64Value |= right.UInt64Value; break;
 7104                            default: UnreachableCase(code); break;
 7105                        }
 7106                        break;
 7107                    case ExpressionType.ExclusiveOr:
 7108                        switch (code)
 7109                        {
 7110                            case TypeCode.Char: left.CharValue ^= right.CharValue; break;
 7111                            case TypeCode.SByte: left.SByteValue ^= right.SByteValue; break;
 7112                            case TypeCode.Byte: left.ByteValue ^= right.ByteValue; break;
 7113                            case TypeCode.Int16: left.Int16Value ^= right.Int16Value; break;
 7114                            case TypeCode.UInt16: left.UInt16Value ^= right.UInt16Value; break;
 7115                            case TypeCode.Int32: left.Int32Value ^= right.Int32Value; break;
 7116                            case TypeCode.UInt32: left.UInt32Value ^= right.UInt32Value; break;
 7117                            case TypeCode.Int64: left.Int64Value ^= right.Int64Value; break;
 7118                            case TypeCode.UInt64: left.UInt64Value ^= right.UInt64Value; break;
 7119                            default: UnreachableCase(code); break;
 7120                        }
 7121                        break;
 7122                    case ExpressionType.LeftShift:
 7123                        switch (code)
 7124                        {
 7125                            case TypeCode.Char: left.CharValue <<= right.CharValue; break;
 7126                            case TypeCode.SByte: left.SByteValue <<= right.SByteValue; break;
 7127                            case TypeCode.Byte: left.ByteValue <<= right.ByteValue; break;
 7128                            case TypeCode.Int16: left.Int16Value <<= right.Int16Value; break;
 7129                            case TypeCode.UInt16: left.UInt16Value <<= right.UInt16Value; break;
 7130                            case TypeCode.Int32: left.Int32Value <<= right.Int32Value; break;
 7131                            case TypeCode.UInt32: left.UInt32Value <<= (int)right.UInt32Value; break;
 7132                            case TypeCode.Int64: left.Int64Value <<= (int)right.Int64Value; break;
 7133                            case TypeCode.UInt64: left.UInt64Value <<= (int)right.UInt64Value; break;
 7134                            default: UnreachableCase(code); break;
 7135                        }
 7136                        break;
 7137                    case ExpressionType.RightShift:
 7138                        switch (code)
 7139                        {
 7140                            case TypeCode.Char: left.CharValue >>= right.CharValue; break;
 7141                            case TypeCode.SByte: left.SByteValue >>= right.SByteValue; break;
 7142                            case TypeCode.Byte: left.ByteValue >>= right.ByteValue; break;
 7143                            case TypeCode.Int16: left.Int16Value >>= right.Int16Value; break;
 7144                            case TypeCode.UInt16: left.UInt16Value >>= right.UInt16Value; break;
 7145                            case TypeCode.Int32: left.Int32Value >>= right.Int32Value; break;
 7146                            case TypeCode.UInt32: left.UInt32Value >>= (int)right.UInt32Value; break;
 7147                            case TypeCode.Int64: left.Int64Value >>= (int)right.Int64Value; break;
 7148                            case TypeCode.UInt64: left.UInt64Value >>= (int)right.UInt64Value; break;
 7149                            default: UnreachableCase(code); break;
 7150                        }
 7151                        break;
 7152                    default: UnreachableCase(nodeType); break;
 7153                }
 7154            }
 7155
 7156            [MethodImpl(MethodImplOptions.AggressiveInlining)]
 7157            internal static bool TrySetPrimitiveValueToDefault(ref PValue value, TypeCode code)
 7158            {
 7159                switch (code)
 7160                {
 7161                    case TypeCode.Char: value.CharValue = default; break;
 7162                    case TypeCode.SByte: value.SByteValue = default; break;
 7163                    case TypeCode.Byte: value.ByteValue = default; break;
 7164                    case TypeCode.Int16: value.Int16Value = default; break;
 7165                    case TypeCode.UInt16: value.UInt16Value = default; break;
 7166                    case TypeCode.Int32: value.Int32Value = default; break;
 7167                    case TypeCode.UInt32: value.UInt32Value = default; break;
 7168                    case TypeCode.Int64: value.Int64Value = default; break;
 7169                    case TypeCode.UInt64: value.UInt64Value = default; break;
 7170                    case TypeCode.Single: value.SingleValue = default; break;
 7171                    case TypeCode.Double: value.DoubleValue = default; break;
 7172                    default: return false;
 7173                }
 7174                return true;
 7175            }
 7176
 7177            /// <summary>Fast, mostly negative check to skip or proceed with interpretation.
 7178            /// Depending on the context you may avoid calling it because you know the interpreted expression beforehand
 7179            [MethodImpl(MethodImplOptions.AggressiveInlining)]
 7180            public static bool IsCandidateForInterpretation(Expression expr)
 7181            {
 7182                var nodeType = expr.NodeType;
 7183                return
 7184                    nodeType == ExpressionType.Constant |
 7185                    nodeType == ExpressionType.Default |
 7186                    nodeType == ExpressionType.Convert |
 7187                    nodeType == ExpressionType.Not |
 7188                    nodeType == ExpressionType.Negate |
 7189                    expr is BinaryExpression;
 7190            }
 7191
 7192#if INTERPRETATION_DIAGNOSTICS
 7193
 7194            [UnconditionalSuppressMessage("Trimming", "IL2026:Members annotated with 'RequiresUnreferencedCodeAttribute'
 7195            [UnconditionalSuppressMessage("Trimming", "IL2075:Members annotated with 'RequiresUnreferencedCodeAttribute'
 7196            private static void CollectCallingTestName()
 7197            {
 7198                var stackTrace = new StackTrace();
 7199                var frames = stackTrace.GetFrames();
 7200
 7201                // Skip this method and its immediate caller, and start from the outer callers
 7202                var found = false;
 7203                for (int i = 3; i < frames.Length; ++i)
 7204                {
 7205                    var frame = frames[i];
 7206                    var method = frame.GetMethod();
 7207                    var type = method?.DeclaringType;
 7208                    if (type == null)
 7209                        continue;
 7210
 7211                    var ifaces = type.GetInterfaces();
 7212                    if (ifaces.Length == 0)
 7213                        continue;
 7214
 7215                    foreach (var iface in ifaces)
 7216                        if (iface.Name.Contains("Test"))
 7217                        {
 7218                            found = true;
 7219                            break;
 7220                        }
 7221
 7222                    if (found)
 7223                    {
 7224                        found = true;
 7225                        Console.WriteLine($"Interpretation in: {type.Name}.{method.Name}");
 7226                        break; // collect the first found thing in stack trace
 7227                    }
 7228                }
 7229
 7230                if (!found)
 7231                {
 7232                    var methodTrace = string.Join("; ", frames.Skip(3).Select(f => f.GetMethod().Name).ToArray());
 7233                    Console.WriteLine($"Interpretation in: not found in stack trace: {methodTrace}");
 7234                }
 7235            }
 7236#endif
 7237
 7238            /// <summary>Wraps `TryInterpretPrimitive` in the try catch block.
 7239            /// In case of exception FEC will emit the whole computation to throw exception in the invocation phase</sum
 7240            public static bool TryInterpretBool(out bool result, Expression expr, CompilerFlags flags)
 7241            {
 7242                Debug.Assert(expr.Type.IsPrimitive);
 7243                result = false;
 7244                if ((flags & CompilerFlags.DisableInterpreter) != 0)
 7245                    return false;
 7246                try
 7247                {
 7248                    var ok = TryInterpretBool(ref result, expr, expr.NodeType);
 7249#if INTERPRETATION_DIAGNOSTICS
 7250                    if (ok) CollectCallingTestName();
 7251#endif
 7252                    return ok;
 7253                }
 7254                catch
 7255                {
 7256                    // ignore exception and return the false and rethrow the exception in the invocation time
 7257                    return false;
 7258                }
 7259            }
 7260
 7261            // todo: @perf try split to `TryInterpretBinary` overload to streamline the calls for TryEmitConditional and
 7262            /// <summary>Tries to interpret the expression of the Primitive type of Constant, Convert, Logical, Comparis
 7263            internal static bool TryInterpretBool(ref bool resultBool, Expression expr, ExpressionType nodeType)
 7264            {
 7265                // what operations are supported, to get the boolean result?
 7266                // yes: not, logical, comparison, default
 7267                // not: negate, arithmetic, convert to bool
 7268                if (nodeType == ExpressionType.Not)
 7269                {
 7270                    var operandExpr = ((UnaryExpression)expr).Operand;
 7271                    if (operandExpr is ConstantExpression co)
 7272                        resultBool = (bool)co.Value;
 7273                    else if (!TryInterpretBool(ref resultBool, operandExpr, operandExpr.NodeType))
 7274                        return false;
 7275
 7276                    resultBool = !resultBool;
 7277                    return true;
 7278                }
 7279
 7280                if (nodeType == ExpressionType.AndAlso |
 7281                    nodeType == ExpressionType.OrElse)
 7282                {
 7283                    var binaryExpr = (BinaryExpression)expr;
 7284
 7285                    // Interpreting the left part as the first candidate for the result
 7286                    var left = binaryExpr.Left;
 7287                    if (left is ConstantExpression lc)
 7288                        resultBool = (bool)lc.Value;
 7289                    else if (!TryInterpretBool(ref resultBool, left, left.NodeType))
 7290                        return false;
 7291
 7292                    // Short circuit the interpretation, because this is an actual logic of these logical operations
 7293                    if (resultBool & nodeType == ExpressionType.OrElse ||
 7294                        !resultBool & nodeType == ExpressionType.AndAlso)
 7295                        return true;
 7296
 7297                    // If the first part is not enough to decide of the expression result, go right
 7298                    var right = binaryExpr.Right;
 7299                    if (right is ConstantExpression rc)
 7300                    {
 7301                        resultBool = (bool)rc.Value;
 7302                        return true;
 7303                    }
 7304                    return TryInterpretBool(ref resultBool, right, right.NodeType);
 7305                }
 7306
 7307                if (nodeType == ExpressionType.Equal |
 7308                    nodeType == ExpressionType.NotEqual)
 7309                {
 7310                    var binaryExpr = (BinaryExpression)expr;
 7311                    var right = binaryExpr.Right;
 7312                    var left = binaryExpr.Left;
 7313                    var leftCode = Type.GetTypeCode(left.Type);
 7314                    if (leftCode == TypeCode.Boolean)
 7315                    {
 7316                        var leftBool = false;
 7317                        if (left is ConstantExpression lc)
 7318                            leftBool = (bool)lc.Value;
 7319                        else if (!TryInterpretBool(ref leftBool, left, left.NodeType))
 7320                            return false;
 7321
 7322                        var rightBool = false;
 7323                        if (right is ConstantExpression rc)
 7324                            rightBool = (bool)rc.Value;
 7325                        else if (!TryInterpretBool(ref rightBool, right, right.NodeType))
 7326                            return false;
 7327
 7328                        resultBool = nodeType == ExpressionType.Equal ? leftBool == rightBool : leftBool != rightBool;
 7329                        return true;
 7330                    }
 7331                    if (leftCode == TypeCode.Int32)
 7332                    {
 7333                        var leftInt = 0;
 7334                        if (left is ConstantExpression lc)
 7335                            leftInt = (int)lc.Value;
 7336                        else if (!TryInterpretInt(ref leftInt, left, left.NodeType))
 7337                            return false;
 7338
 7339                        var rightInt = 0;
 7340                        if (right is ConstantExpression rc)
 7341                            rightInt = (int)rc.Value;
 7342                        else if (!TryInterpretInt(ref rightInt, right, right.NodeType))
 7343                            return false;
 7344
 7345                        resultBool = nodeType == ExpressionType.Equal ? leftInt == rightInt : leftInt != rightInt;
 7346                        return true;
 7347                    }
 7348                    if (leftCode == TypeCode.Decimal)
 7349                    {
 7350                        decimal decimalLeft = default;
 7351                        if (left is ConstantExpression lc)
 7352                            decimalLeft = (decimal)lc.Value;
 7353                        else if (!TryInterpretDecimal(ref decimalLeft, left, left.NodeType))
 7354                            return false;
 7355
 7356                        decimal rightDec = default;
 7357                        if (right is ConstantExpression rc)
 7358                            rightDec = (decimal)rc.Value;
 7359                        else if (!TryInterpretDecimal(ref rightDec, right, right.NodeType))
 7360                            return false;
 7361
 7362                        resultBool = nodeType == ExpressionType.Equal ? decimalLeft == rightDec : decimalLeft != rightDe
 7363                        return true;
 7364                    }
 7365                    // not a bool, int, or decimal
 7366                    {
 7367                        PValue leftVal = default;
 7368                        if (left is ConstantExpression lc && !TryUnboxToPrimitiveValue(ref leftVal, lc.Value, leftCode) 
 7369                            !TryInterpretPrimitiveValue(ref leftVal, left, leftCode, left.NodeType))
 7370                            return false;
 7371
 7372                        PValue rightVal = default;
 7373                        if (right is ConstantExpression rc && !TryUnboxToPrimitiveValue(ref rightVal, rc.Value, leftCode
 7374                            !TryInterpretPrimitiveValue(ref rightVal, right, leftCode, right.NodeType))
 7375                            return false;
 7376
 7377                        resultBool = leftCode switch
 7378                        {
 7379                            TypeCode.Char => leftVal.CharValue == rightVal.CharValue,
 7380                            TypeCode.SByte => leftVal.SByteValue == rightVal.SByteValue,
 7381                            TypeCode.Byte => leftVal.ByteValue == rightVal.ByteValue,
 7382                            TypeCode.Int16 => leftVal.Int16Value == rightVal.Int16Value,
 7383                            TypeCode.UInt16 => leftVal.UInt16Value == rightVal.UInt16Value,
 7384                            TypeCode.Int32 => leftVal.Int32Value == rightVal.Int32Value,
 7385                            TypeCode.UInt32 => leftVal.UInt32Value == rightVal.UInt32Value,
 7386                            TypeCode.Int64 => leftVal.Int64Value == rightVal.Int64Value,
 7387                            TypeCode.UInt64 => leftVal.UInt64Value == rightVal.UInt64Value,
 7388                            TypeCode.Single => leftVal.SingleValue == rightVal.SingleValue,
 7389                            TypeCode.Double => leftVal.DoubleValue == rightVal.DoubleValue,
 7390                            _ => UnreachableCase(leftCode, false),
 7391                        };
 7392                        resultBool = nodeType == ExpressionType.Equal ? resultBool : !resultBool;
 7393                        return true;
 7394                    }
 7395                }
 7396
 7397                if (nodeType == ExpressionType.GreaterThan |
 7398                    nodeType == ExpressionType.GreaterThanOrEqual |
 7399                    nodeType == ExpressionType.LessThan |
 7400                    nodeType == ExpressionType.LessThanOrEqual)
 7401                {
 7402                    var binaryExpr = (BinaryExpression)expr;
 7403                    var left = binaryExpr.Left;
 7404                    var right = binaryExpr.Right;
 7405                    var leftCode = Type.GetTypeCode(left.Type);
 7406                    Debug.Assert(leftCode != TypeCode.Boolean, "Boolean values are not comparable by less or greater");
 7407
 7408                    if (leftCode == TypeCode.Int32)
 7409                    {
 7410                        int intLeft = 0;
 7411                        if (left is ConstantExpression lc)
 7412                            intLeft = (int)lc.Value;
 7413                        else if (!TryInterpretInt(ref intLeft, left, left.NodeType))
 7414                            return false;
 7415
 7416                        int rightInt = 0;
 7417                        if (right is ConstantExpression rc)
 7418                            rightInt = (int)rc.Value;
 7419                        else if (!TryInterpretInt(ref rightInt, right, right.NodeType))
 7420                            return false;
 7421
 7422                        resultBool = nodeType switch
 7423                        {
 7424                            ExpressionType.GreaterThan => intLeft > rightInt,
 7425                            ExpressionType.GreaterThanOrEqual => intLeft >= rightInt,
 7426                            ExpressionType.LessThan => intLeft < rightInt,
 7427                            ExpressionType.LessThanOrEqual => intLeft <= rightInt,
 7428                            _ => UnreachableCase(nodeType, false),
 7429                        };
 7430                        return true;
 7431                    }
 7432                    if (leftCode == TypeCode.Decimal)
 7433                    {
 7434                        decimal leftDec = default;
 7435                        if (left is ConstantExpression lc)
 7436                            leftDec = (decimal)lc.Value;
 7437                        else if (!TryInterpretDecimal(ref leftDec, left, left.NodeType))
 7438                            return false;
 7439
 7440                        decimal rightDec = default;
 7441                        if (right is ConstantExpression rc)
 7442                            rightDec = (decimal)rc.Value;
 7443                        else if (!TryInterpretDecimal(ref rightDec, right, right.NodeType))
 7444                            return false;
 7445
 7446                        resultBool = nodeType switch
 7447                        {
 7448                            ExpressionType.GreaterThan => leftDec > rightDec,
 7449                            ExpressionType.GreaterThanOrEqual => leftDec >= rightDec,
 7450                            ExpressionType.LessThan => leftDec < rightDec,
 7451                            ExpressionType.LessThanOrEqual => leftDec <= rightDec,
 7452                            _ => UnreachableCase(nodeType, false),
 7453                        };
 7454                        return true;
 7455                    }
 7456                    // not a bool, int, or decimal
 7457                    {
 7458                        PValue leftVal = default;
 7459                        if (left is ConstantExpression lc && !TryUnboxToPrimitiveValue(ref leftVal, lc.Value, leftCode) 
 7460                            !TryInterpretPrimitiveValue(ref leftVal, left, leftCode, left.NodeType))
 7461                            return false;
 7462
 7463                        PValue rightVal = default;
 7464                        if (right is ConstantExpression rc && !TryUnboxToPrimitiveValue(ref rightVal, rc.Value, leftCode
 7465                            !TryInterpretPrimitiveValue(ref rightVal, right, leftCode, right.NodeType))
 7466                            return false;
 7467
 7468                        resultBool = ComparePrimitiveValues(ref leftVal, ref rightVal, leftCode, nodeType);
 7469                        return true;
 7470                    }
 7471                }
 7472
 7473                if (expr is ConstantExpression constExpr)
 7474                {
 7475                    resultBool = (bool)constExpr.Value;
 7476                    return true;
 7477                }
 7478
 7479                if (nodeType == ExpressionType.Default)
 7480                {
 7481                    resultBool = false;
 7482                    return true;
 7483                }
 7484
 7485                return false;
 7486            }
 7487
 7488            /// <summary>Tries to interpret the expression of the Primitive type of Constant, Convert, Logical, Comparis
 7489            internal static bool TryInterpretDecimal(ref decimal resultDec, Expression expr, ExpressionType nodeType)
 7490            {
 7491                // What operations are supported, to get the decimal result:
 7492                // yes: arithmetic, negate, default, convert
 7493                // no: not, logical, comparison
 7494
 7495                if (IsArithmeticBinary(nodeType))
 7496                {
 7497                    var binaryExpr = (BinaryExpression)expr;
 7498                    var left = binaryExpr.Left;
 7499                    if (left is ConstantExpression lc)
 7500                        resultDec = (decimal)lc.Value;
 7501                    else if (!TryInterpretDecimal(ref resultDec, left, left.NodeType))
 7502                        return false;
 7503
 7504                    decimal rightDec = default;
 7505                    var right = binaryExpr.Right;
 7506                    if (right is ConstantExpression rc)
 7507                        rightDec = (decimal)rc.Value;
 7508                    else if (!TryInterpretDecimal(ref rightDec, right, right.NodeType))
 7509                        return false;
 7510
 7511                    switch (nodeType)
 7512                    {
 7513                        case ExpressionType.Add: resultDec += rightDec; break;
 7514                        case ExpressionType.Subtract: resultDec -= rightDec; break;
 7515                        case ExpressionType.Multiply: resultDec *= rightDec; break;
 7516                        case ExpressionType.Divide: resultDec /= rightDec; break;
 7517                        case ExpressionType.Modulo: resultDec %= rightDec; break;
 7518                        default: UnreachableCase(nodeType); break;
 7519                    }
 7520                    return true;
 7521                }
 7522
 7523                if (nodeType == ExpressionType.Negate)
 7524                {
 7525                    var operandExpr = ((UnaryExpression)expr).Operand;
 7526                    if (operandExpr is ConstantExpression co)
 7527                        resultDec = (decimal)co.Value;
 7528                    else if (!TryInterpretDecimal(ref resultDec, operandExpr, operandExpr.NodeType))
 7529                        return false;
 7530
 7531                    resultDec = -resultDec;
 7532                    return true;
 7533                }
 7534
 7535                if (expr is ConstantExpression constExpr)
 7536                {
 7537                    resultDec = (decimal)constExpr.Value;
 7538                    return true;
 7539                }
 7540
 7541                if (nodeType == ExpressionType.Default)
 7542                {
 7543                    resultDec = default;
 7544                    return true;
 7545                }
 7546
 7547                if (nodeType == ExpressionType.Convert)
 7548                {
 7549                    var operandExpr = ((UnaryExpression)expr).Operand;
 7550                    var operandCode = Type.GetTypeCode(operandExpr.Type);
 7551                    Debug.Assert(operandCode != TypeCode.Boolean,
 7552                        "Operand may be a decimal but cannot be bool, because there is no conversation from bool to the 
 7553
 7554                    PValue operandVal = default;
 7555                    if (operandExpr is ConstantExpression co && !TryUnboxToPrimitiveValue(ref operandVal, co.Value, oper
 7556                        !TryInterpretPrimitiveValue(ref operandVal, operandExpr, operandCode, operandExpr.NodeType))
 7557                        return false;
 7558
 7559                    resultDec = operandCode switch
 7560                    {
 7561                        TypeCode.Char => operandVal.CharValue,
 7562                        TypeCode.SByte => operandVal.SByteValue,
 7563                        TypeCode.Byte => operandVal.ByteValue,
 7564                        TypeCode.Int16 => operandVal.Int16Value,
 7565                        TypeCode.UInt16 => operandVal.UInt16Value,
 7566                        TypeCode.Int32 => operandVal.Int32Value,
 7567                        TypeCode.UInt32 => operandVal.UInt32Value,
 7568                        TypeCode.Int64 => operandVal.Int64Value,
 7569                        TypeCode.UInt64 => operandVal.UInt64Value,
 7570                        TypeCode.Single => (decimal)operandVal.SingleValue,
 7571                        TypeCode.Double => (decimal)operandVal.DoubleValue,
 7572                        _ => UnreachableCase(operandCode, default(decimal)),
 7573                    };
 7574                    return true;
 7575                }
 7576
 7577                return false;
 7578            }
 7579
 7580            /// <summary>Tries to interpret the expression of the Primitive type of Constant, Convert, Logical, Comparis
 7581            /// Returns `false` if it failed to do so.</summary>
 7582            internal static bool TryInterpretInt(ref int resultInt, Expression expr, ExpressionType nodeType)
 7583            {
 7584                // What is supported for the int result
 7585                // yes: arithmetic, convert, default
 7586                // no: not, logical, comparison
 7587                if (IsArithmeticBinary(nodeType))
 7588                {
 7589                    var binaryExpr = (BinaryExpression)expr;
 7590                    var left = binaryExpr.Left;
 7591                    if (left is ConstantExpression lc)
 7592                        resultInt = (int)lc.Value;
 7593                    else if (!TryInterpretInt(ref resultInt, left, left.NodeType))
 7594                        return false;
 7595
 7596                    int rightVal = 0;
 7597                    var right = binaryExpr.Right;
 7598                    if (right is ConstantExpression rc)
 7599                        rightVal = (int)rc.Value;
 7600                    else if (!TryInterpretInt(ref rightVal, right, right.NodeType))
 7601                        return false;
 7602
 7603                    resultInt = nodeType switch
 7604                    {
 7605                        ExpressionType.Add => resultInt + rightVal,
 7606                        ExpressionType.Subtract => resultInt - rightVal,
 7607                        ExpressionType.Multiply => resultInt * rightVal,
 7608                        ExpressionType.Divide => resultInt / rightVal,
 7609                        ExpressionType.Modulo => resultInt % rightVal,
 7610                        ExpressionType.LeftShift => resultInt << rightVal,
 7611                        ExpressionType.RightShift => resultInt >> rightVal,
 7612                        ExpressionType.And => resultInt & rightVal,
 7613                        ExpressionType.Or => resultInt | rightVal,
 7614                        ExpressionType.ExclusiveOr => resultInt ^ rightVal,
 7615                        ExpressionType.Power => (int)Math.Pow(resultInt, rightVal),
 7616                        _ => UnreachableCase(nodeType, 0),
 7617                    };
 7618                    return true;
 7619                }
 7620
 7621                if (nodeType == ExpressionType.Negate)
 7622                {
 7623                    var operandExpr = ((UnaryExpression)expr).Operand;
 7624                    if (operandExpr is ConstantExpression co)
 7625                        resultInt = (int)co.Value;
 7626                    else if (!TryInterpretInt(ref resultInt, operandExpr, operandExpr.NodeType))
 7627                        return false;
 7628
 7629                    resultInt = -resultInt;
 7630                    return true;
 7631                }
 7632
 7633                if (expr is ConstantExpression constExpr)
 7634                {
 7635                    resultInt = (int)constExpr.Value;
 7636                    return true;
 7637                }
 7638
 7639                if (nodeType == ExpressionType.Default)
 7640                {
 7641                    resultInt = 0;
 7642                    return true;
 7643                }
 7644
 7645                if (nodeType == ExpressionType.Convert)
 7646                {
 7647                    var operandExpr = ((UnaryExpression)expr).Operand;
 7648                    var operandCode = Type.GetTypeCode(operandExpr.Type);
 7649                    Debug.Assert(operandCode != TypeCode.Boolean,
 7650                        "Operand may be a decimal but cannot be bool, because there is no conversation from bool to the 
 7651
 7652                    if (operandCode != TypeCode.Decimal)
 7653                    {
 7654                        PValue operandVal = default;
 7655                        if (operandExpr is ConstantExpression co && !TryUnboxToPrimitiveValue(ref operandVal, co.Value, 
 7656                            !TryInterpretPrimitiveValue(ref operandVal, operandExpr, operandCode, operandExpr.NodeType))
 7657                            return false;
 7658
 7659                        resultInt = operandCode switch
 7660                        {
 7661                            TypeCode.Char => operandVal.CharValue,
 7662                            TypeCode.SByte => operandVal.SByteValue,
 7663                            TypeCode.Byte => operandVal.ByteValue,
 7664                            TypeCode.Int16 => operandVal.Int16Value,
 7665                            TypeCode.UInt16 => operandVal.UInt16Value,
 7666                            TypeCode.Int32 => operandVal.Int32Value,
 7667                            TypeCode.UInt32 => (int)operandVal.UInt32Value,
 7668                            TypeCode.Int64 => (int)operandVal.Int64Value,
 7669                            TypeCode.UInt64 => (int)operandVal.UInt64Value,
 7670                            TypeCode.Single => (int)operandVal.SingleValue,
 7671                            TypeCode.Double => (int)operandVal.DoubleValue,
 7672                            _ => UnreachableCase(operandCode, 0),
 7673                        };
 7674                        return true;
 7675                    }
 7676                    // then for the decimal
 7677                    {
 7678                        decimal resultDec = default;
 7679                        if (operandExpr is ConstantExpression co)
 7680                            resultDec = (decimal)co.Value;
 7681                        else if (!TryInterpretDecimal(ref resultDec, operandExpr, operandExpr.NodeType))
 7682                            return false;
 7683
 7684                        resultInt = (int)resultDec;
 7685                        return true;
 7686                    }
 7687                }
 7688                return false;
 7689            }
 7690
 7691            /// <summary>Tries to interpret the expression of the Primitive type of Constant, Convert, Logical, Comparis
 7692            /// Returns `false` if it is failed to do so.</summary>
 7693            internal static bool TryInterpretPrimitiveValue(ref PValue result, Expression expr, TypeCode exprCode, Expre
 7694            {
 7695                // What is supported for the non-boolean, non-decimal result
 7696                // yes: arithmetic, convert, default
 7697                // no: not, logical, comparison
 7698                if (IsArithmeticBinary(nodeType))
 7699                {
 7700                    var binaryExpr = (BinaryExpression)expr;
 7701                    var left = binaryExpr.Left;
 7702                    var leftCode = Type.GetTypeCode(left.Type);
 7703                    if (left is ConstantExpression lc && !TryUnboxToPrimitiveValue(ref result, lc.Value, leftCode) ||
 7704                        !TryInterpretPrimitiveValue(ref result, left, leftCode, left.NodeType))
 7705                        return false;
 7706
 7707                    PValue rightVal = default;
 7708                    var right = binaryExpr.Right;
 7709                    // Using the leftCode to interpret the right part of the binary expression,
 7710                    // because for supported operations left and right types are the same
 7711                    if (right is ConstantExpression rc && !TryUnboxToPrimitiveValue(ref rightVal, rc.Value, leftCode) ||
 7712                        !TryInterpretPrimitiveValue(ref rightVal, right, leftCode, right.NodeType))
 7713                        return false;
 7714
 7715                    DoArithmeticForPrimitiveValues(ref result, ref rightVal, leftCode, nodeType);
 7716                    return true;
 7717                }
 7718
 7719                if (nodeType == ExpressionType.Negate)
 7720                {
 7721                    var operandExpr = ((UnaryExpression)expr).Operand;
 7722                    var operandCode = Type.GetTypeCode(operandExpr.Type);
 7723                    if (operandExpr is ConstantExpression co && !TryUnboxToPrimitiveValue(ref result, co.Value, operandC
 7724                        !TryInterpretPrimitiveValue(ref result, operandExpr, operandCode, operandExpr.NodeType))
 7725                        return false;
 7726
 7727                    NegatePrimitiveValue(ref result, operandCode);
 7728                    return true;
 7729                }
 7730
 7731                if (expr is ConstantExpression constExpr)
 7732                    return TryUnboxToPrimitiveValue(ref result, constExpr.Value, exprCode);
 7733
 7734                if (nodeType == ExpressionType.Default)
 7735                    return TrySetPrimitiveValueToDefault(ref result, exprCode);
 7736
 7737                if (nodeType == ExpressionType.Convert)
 7738                {
 7739                    var operandExpr = ((UnaryExpression)expr).Operand;
 7740                    var operandCode = Type.GetTypeCode(operandExpr.Type);
 7741                    Debug.Assert(operandCode != TypeCode.Boolean,
 7742                        "Operand may be a decimal but cannot be bool, because there is no conversation from bool to the 
 7743
 7744                    if (operandCode != TypeCode.Decimal)
 7745                    {
 7746                        if (operandExpr is ConstantExpression co && !TryUnboxToPrimitiveValue(ref result, co.Value, oper
 7747                            !TryInterpretPrimitiveValue(ref result, operandExpr, operandCode, operandExpr.NodeType))
 7748                            return false;
 7749
 7750                        if (exprCode != operandCode)
 7751                            ConvertPrimitiveValueFromTo(ref result, operandCode, exprCode);
 7752                        return true;
 7753                    }
 7754                    // then for the decimal
 7755                    {
 7756                        decimal operandDec = default;
 7757                        if (operandExpr is ConstantExpression co)
 7758                            operandDec = (decimal)co.Value;
 7759                        else if (!TryInterpretDecimal(ref operandDec, operandExpr, operandExpr.NodeType))
 7760                            return false;
 7761
 7762                        switch (exprCode)
 7763                        {
 7764                            case TypeCode.Char: result.CharValue = (char)operandDec; break;
 7765                            case TypeCode.SByte: result.SByteValue = (sbyte)operandDec; break;
 7766                            case TypeCode.Byte: result.ByteValue = (byte)operandDec; break;
 7767                            case TypeCode.Int16: result.Int16Value = (short)operandDec; break;
 7768                            case TypeCode.UInt16: result.UInt16Value = (ushort)operandDec; break;
 7769                            case TypeCode.Int32: result.Int32Value = (int)operandDec; break;
 7770                            case TypeCode.UInt32: result.UInt32Value = (uint)operandDec; break;
 7771                            case TypeCode.Int64: result.Int64Value = (long)operandDec; break;
 7772                            case TypeCode.UInt64: result.UInt64Value = (ulong)operandDec; break;
 7773                            case TypeCode.Single: result.SingleValue = (float)operandDec; break;
 7774                            case TypeCode.Double: result.DoubleValue = (double)operandDec; break;
 7775                            default:
 7776                                // todo: @feature #472 support conversion to nullable, put nullable marker into PValue o
 7777                                return false;
 7778                        }
 7779                        return true;
 7780                    }
 7781                }
 7782                return false;
 7783            }
 7784        }
 7785    }
 7786
 7787    /// <summary>
 7788    /// Helpers targeting the performance. Extensions method names may be a bit funny (non standard),
 7789    /// in order to prevent conflicts with YOUR helpers with standard names
 7790    /// </summary>
 7791    internal static class Tools
 7792    {
 7793        public static Expression AsExpr(this object obj) => obj as Expression ?? Constant(obj);
 7794        public static Expression[] AsExprs(this object[] obj)
 7795        {
 7796            var exprs = new Expression[obj.Length];
 7797            for (var i = 0; i < obj.Length; i++)
 7798                exprs[i] = obj[i].AsExpr();
 7799            return exprs;
 7800        }
 7801
 7802        /// <summary>Returns true if class is compiler generated. Checking for CompilerGeneratedAttribute
 7803        /// is not enough, because this attribute is not applied for classes generated from "async/await".</summary>
 7804        [MethodImpl((MethodImplOptions)256)]
 7805        public static bool IsCompilerGenerated(this Type type) =>
 7806            type.Name[0] == '<'; // consider the types with obstruct names like `<>blah` as compiler-generated
 7807
 7808        [MethodImpl((MethodImplOptions)256)]
 7809        internal static bool IsUnsigned(this Type type) =>
 7810            type == typeof(byte) ||
 7811            type == typeof(ushort) ||
 7812            type == typeof(uint) ||
 7813            type == typeof(ulong);
 7814
 7815        [MethodImpl((MethodImplOptions)256)]
 7816        internal static bool IsFloatingPoint(this Type type) =>
 7817            type == typeof(float) ||
 7818            type == typeof(double);
 7819
 7820        internal static bool IsPrimitiveWithZeroDefaultExceptDecimal(this Type type)
 7821        {
 7822            switch (Type.GetTypeCode(type))
 7823            {
 7824                case TypeCode.Boolean:
 7825                case TypeCode.Char:
 7826                case TypeCode.SByte:
 7827                case TypeCode.Byte:
 7828                case TypeCode.Int16:
 7829                case TypeCode.UInt16:
 7830                case TypeCode.Int32:
 7831                case TypeCode.UInt32:
 7832                case TypeCode.Int64:
 7833                case TypeCode.UInt64:
 7834                case TypeCode.Single:
 7835                case TypeCode.Double:
 7836                    return true;
 7837                default:
 7838                    return false;
 7839            }
 7840        }
 7841
 7842        [RequiresUnreferencedCode(Trimming.Message)]
 7843        [MethodImpl((MethodImplOptions)256)]
 7844        public static bool IsNullable(this Type type) =>
 7845            (type.IsValueType & type.IsGenericType) && type.GetGenericTypeDefinition() == typeof(Nullable<>);
 7846
 7847        [RequiresUnreferencedCode(Trimming.Message)]
 7848        [MethodImpl((MethodImplOptions)256)]
 7849        public static Type GetUnderlyingNullableTypeOrNull(this Type type) =>
 7850            (type.IsValueType & type.IsGenericType) && type.GetGenericTypeDefinition() == typeof(Nullable<>) ? type.GetG
 7851
 7852        [RequiresUnreferencedCode(Trimming.Message)]
 7853        [MethodImpl((MethodImplOptions)256)]
 7854        public static Type GetUnderlyingNullableTypeUnsafe(this Type type) => type.GetGenericArguments()[0];
 7855
 7856        [RequiresUnreferencedCode(Trimming.Message)]
 7857        [MethodImpl((MethodImplOptions)256)]
 7858        public static Type GetNonNullableOrSelf(this Type type) => type.IsNullable() ? type.GetGenericArguments()[0] : t
 7859
 7860        [RequiresUnreferencedCode(Trimming.Message)]
 7861        [MethodImpl((MethodImplOptions)256)]
 7862        public static Type GetNullable(this Type type) => typeof(Nullable<>).MakeGenericType(type);
 7863
 7864        public static string GetArithmeticBinaryOperatorMethodName(this ExpressionType nodeType) =>
 7865            nodeType switch
 7866            {
 7867                ExpressionType.Add => "op_Addition",
 7868                ExpressionType.AddChecked => "op_Addition",
 7869                ExpressionType.Subtract => "op_Subtraction",
 7870                ExpressionType.SubtractChecked => "op_Subtraction",
 7871                ExpressionType.Multiply => "op_Multiply",
 7872                ExpressionType.MultiplyChecked => "op_Multiply",
 7873                ExpressionType.Divide => "op_Division",
 7874                ExpressionType.Modulo => "op_Modulus",
 7875                _ => null
 7876            };
 7877
 7878        internal static bool IsAssignNodeType(this ExpressionType nodeType) => nodeType switch
 7879        {
 7880            ExpressionType.Assign => true,
 7881            ExpressionType.PowerAssign => true,
 7882            ExpressionType.AndAssign => true,
 7883            ExpressionType.OrAssign => true,
 7884            ExpressionType.AddAssign => true,
 7885            ExpressionType.ExclusiveOrAssign => true,
 7886            ExpressionType.AddAssignChecked => true,
 7887            ExpressionType.SubtractAssign => true,
 7888            ExpressionType.SubtractAssignChecked => true,
 7889            ExpressionType.MultiplyAssign => true,
 7890            ExpressionType.MultiplyAssignChecked => true,
 7891            ExpressionType.DivideAssign => true,
 7892            ExpressionType.LeftShiftAssign => true,
 7893            ExpressionType.RightShiftAssign => true,
 7894            ExpressionType.ModuloAssign => true,
 7895            _ => false
 7896        };
 7897
 7898        [MethodImpl((MethodImplOptions)256)]
 7899        internal static bool IsBlockLike(this ExpressionType nodeType) =>
 7900            nodeType == ExpressionType.Try |
 7901            nodeType == ExpressionType.Switch |
 7902            nodeType == ExpressionType.Block |
 7903            nodeType == ExpressionType.Loop;
 7904
 7905        [MethodImpl((MethodImplOptions)256)]
 7906        internal static bool IsReturnable(this ExpressionType nodeType) =>
 7907            nodeType != ExpressionType.Goto &
 7908            nodeType != ExpressionType.Label &
 7909            nodeType != ExpressionType.Throw &&
 7910            !IsBlockLike(nodeType);
 7911
 7912        [MethodImpl((MethodImplOptions)256)]
 7913        internal static bool IsBlockLikeOrConditional(this ExpressionType nodeType) =>
 7914            nodeType == ExpressionType.Conditional | nodeType == ExpressionType.Coalesce ||
 7915            IsBlockLike(nodeType);
 7916
 7917        internal static Expression StripConvertRecursively(this Expression expr) =>
 7918            expr is UnaryExpression convert && convert.NodeType == ExpressionType.Convert
 7919                ? StripConvertRecursively(convert.Operand)
 7920                : expr;
 7921
 7922        internal static bool IsComplexExpression(this Expression expr)
 7923        {
 7924            expr = expr.StripConvertRecursively();
 7925            return expr.NodeType == ExpressionType.Invoke
 7926                || expr.NodeType.IsBlockLikeOrConditional();
 7927        }
 7928
 7929        internal static bool IsConstantOrDefault(this Expression expr)
 7930        {
 7931            var nodeType = StripConvertRecursively(expr).NodeType;
 7932            return nodeType == ExpressionType.Constant
 7933                | nodeType == ExpressionType.Default;
 7934        }
 7935
 7936        internal static bool IsParamOrConstantOrDefault(this Expression expr)
 7937        {
 7938            var nodeType = StripConvertRecursively(expr).NodeType;
 7939            return nodeType == ExpressionType.Parameter
 7940                | nodeType == ExpressionType.Constant
 7941                | nodeType == ExpressionType.Default;
 7942        }
 7943
 7944        internal static string GetCSharpName(this MemberInfo m)
 7945        {
 7946            var name = m.Name;
 7947            if (m is FieldInfo fi && m.DeclaringType.IsValueType)
 7948            {
 7949                // btw, `fi.IsSpecialName` returns `false` :/
 7950                if (name[0] == '<') // a backing field for the properties in struct, e.g. <Key>k__BackingField
 7951                {
 7952                    var end = name.IndexOf('>');
 7953                    if (end > 1)
 7954                        name = name.Substring(1, end - 1);
 7955                }
 7956            }
 7957            return name;
 7958        }
 7959
 7960        [RequiresUnreferencedCode(Trimming.Message)]
 7961        internal static MethodInfo FindMethod(this Type type, string methodName)
 7962        {
 7963            var methods = type.GetMethods();
 7964            for (var i = 0; i < methods.Length; i++)
 7965                if (methods[i].Name == methodName)
 7966                    return methods[i];
 7967            return type.BaseType?.FindMethod(methodName);
 7968        }
 7969
 7970        internal static MethodInfo DelegateTargetGetterMethod =
 7971            typeof(Delegate).GetProperty(nameof(Delegate.Target)).GetMethod;
 7972
 7973        [MethodImpl((MethodImplOptions)256)]
 7974        internal static MethodInfo FindDelegateInvokeMethod(
 7975            [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] this Type type) =>
 7976            type.GetMethod("Invoke");
 7977
 7978        [RequiresUnreferencedCode(Trimming.Message)]
 7979        internal static class NullableReflected<T> where T : struct
 7980        {
 7981            public static readonly Type NullableType = typeof(T?);
 7982            public static readonly MethodInfo ValueGetterMethod =
 7983                NullableType.GetProperty("Value").GetMethod;
 7984            public static readonly MethodInfo HasValueGetterMethod =
 7985                NullableType.GetProperty("HasValue").GetMethod;
 7986            public static readonly FieldInfo ValueField =
 7987                NullableType.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic);
 7988            public static readonly ConstructorInfo Constructor =
 7989                NullableType.GetConstructors()[0];
 7990        }
 7991
 7992        [RequiresUnreferencedCode(Trimming.Message)]
 7993        [MethodImpl((MethodImplOptions)256)]
 7994        internal static MethodInfo GetNullableValueGetterMethod(this Type type) =>
 7995            type == typeof(int?) ? NullableReflected<int>.ValueGetterMethod :
 7996            type == typeof(double?) ? NullableReflected<double>.ValueGetterMethod :
 7997            type.GetProperty("Value").GetMethod;
 7998
 7999        [RequiresUnreferencedCode(Trimming.Message)]
 8000        [MethodImpl((MethodImplOptions)256)]
 8001        internal static MethodInfo GetNullableHasValueGetterMethod(this Type type) =>
 8002            type == typeof(int?) ? NullableReflected<int>.HasValueGetterMethod :
 8003            type == typeof(double?) ? NullableReflected<double>.HasValueGetterMethod :
 8004            type.GetProperty("HasValue").GetMethod;
 8005
 8006        [RequiresUnreferencedCode(Trimming.Message)]
 8007        [MethodImpl((MethodImplOptions)256)]
 8008        internal static FieldInfo GetNullableValueUnsafeAkaGetValueOrDefaultMethod(this Type type) =>
 8009            type == typeof(int?) ? NullableReflected<int>.ValueField :
 8010            type == typeof(double?) ? NullableReflected<double>.ValueField :
 8011            type.GetField("value", BindingFlags.Instance | BindingFlags.NonPublic);
 8012
 8013        [RequiresUnreferencedCode(Trimming.Message)]
 8014        [MethodImpl((MethodImplOptions)256)]
 8015        internal static ConstructorInfo GetNullableConstructor(this Type type) =>
 8016            type == typeof(int?) ? NullableReflected<int>.Constructor :
 8017            type == typeof(double?) ? NullableReflected<double>.Constructor :
 8018            type.GetConstructors()[0];
 8019
 8020        /// <summary>Finds the implicit or explicit conversion operator inType from the sourceType to targetType,
 8021        /// otherwise returns null</summary>
 8022        [RequiresUnreferencedCode(Trimming.Message)]
 8023        public static MethodInfo FindConvertOperator(this Type inType, Type sourceType, Type targetType)
 8024        {
 8025            Debug.Assert(!inType.IsNullable(), "Should not be called for the nullable type");
 8026            Debug.Assert(!inType.IsPrimitive, "Should not be called for the primitive type");
 8027            Debug.Assert(!inType.IsEnum, "Should not be called for the enum type");
 8028
 8029            // note: remember that if inType.IsPrimitive it does contain the explicit or implicit conversion operators a
 8030            if (sourceType == typeof(object) | targetType == typeof(object))
 8031                return null;
 8032
 8033            // conversion operators should be declared as static and public
 8034            var methods = inType.GetMethods(BindingFlags.Static | BindingFlags.Public);
 8035            foreach (var m in methods)
 8036                if (m.IsSpecialName && m.ReturnType == targetType)
 8037                {
 8038                    var n = m.Name;
 8039                    if ((n == "op_Implicit" || n == "op_Explicit") &&
 8040                        m.GetParameters()[0].ParameterType == sourceType)
 8041                        return m;
 8042                }
 8043
 8044            return null;
 8045        }
 8046
 8047        [RequiresUnreferencedCode(Trimming.Message)]
 8048        internal static ConstructorInfo FindSingleParamConstructor(this Type type, Type paramType)
 8049        {
 8050            var ctors = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
 8051            for (var i = 0; i < ctors.Length; i++)
 8052            {
 8053                var ctor = ctors[i];
 8054                var parameters = ctor.GetParameters();
 8055                if (parameters.Length == 1 && parameters[0].ParameterType == paramType)
 8056                    return ctor;
 8057            }
 8058
 8059            return null;
 8060        }
 8061
 8062        public static T[] AsArray<T>(this IEnumerable<T> xs)
 8063        {
 8064            if (xs is T[] array)
 8065                return array;
 8066            return xs == null ? null : xs.ToArray();
 8067        }
 8068
 8069        internal static IList<T> AsList<T>(this IEnumerable<T> source) =>
 8070            source == null ? Empty<T>() : source as IList<T> ?? source.ToList();
 8071
 8072        internal static bool TryGetIndex<T, TEq>(this IList<T> items, out int index, T item, int count,
 8073            TEq eq = default) where TEq : struct, IEq<T>
 8074        {
 8075            for (var i = 0; (uint)i < count; ++i)
 8076                if (eq.Equals(items[i], item))
 8077                {
 8078                    index = i;
 8079                    return true;
 8080                }
 8081            index = -1;
 8082            return false;
 8083        }
 8084
 8085        private static class EmptyArray<T>
 8086        {
 8087            public static readonly T[] Value = new T[0];
 8088        }
 8089
 8090        public static T[] Empty<T>() => EmptyArray<T>.Value;
 8091
 8092        public static Type[] GetParamTypes(IReadOnlyList<PE> paramExprs)
 8093        {
 8094            if (paramExprs == null)
 8095                return Empty<Type>();
 8096
 8097            var count = paramExprs.Count;
 8098            if (count == 0)
 8099                return Empty<Type>();
 8100
 8101            if (count == 1)
 8102                return new[] { paramExprs[0].IsByRef ? paramExprs[0].Type.MakeByRefType() : paramExprs[0].Type };
 8103
 8104            var paramTypes = new Type[count];
 8105            for (var i = 0; i < paramTypes.Length; i++)
 8106            {
 8107                var parameterExpr = paramExprs[i];
 8108                paramTypes[i] = parameterExpr.IsByRef ? parameterExpr.Type.MakeByRefType() : parameterExpr.Type;
 8109            }
 8110
 8111            return paramTypes;
 8112        }
 8113
 8114        public static Type GetFuncOrActionType(Type returnType) =>
 8115            returnType == typeof(void) ? typeof(Action) : typeof(Func<>).MakeGenericType(returnType);
 8116
 8117        public static Type GetFuncOrActionType(Type p, Type returnType) =>
 8118            returnType == typeof(void) ? typeof(Action<>).MakeGenericType(p) : typeof(Func<,>).MakeGenericType(p, return
 8119
 8120        public static Type GetFuncOrActionType(Type p0, Type p1, Type returnType) =>
 8121            returnType == typeof(void) ? typeof(Action<,>).MakeGenericType(p0, p1) : typeof(Func<,,>).MakeGenericType(p0
 8122
 8123        public static Type GetFuncOrActionType(Type p0, Type p1, Type p2, Type returnType) =>
 8124            returnType == typeof(void) ? typeof(Action<,,>).MakeGenericType(p0, p1, p2) : typeof(Func<,,,>).MakeGenericT
 8125
 8126        public static Type GetFuncOrActionType(Type p0, Type p1, Type p2, Type p3, Type returnType) =>
 8127            returnType == typeof(void) ? typeof(Action<,,,>).MakeGenericType(p0, p1, p2, p3) : typeof(Func<,,,,>).MakeGe
 8128
 8129        public static Type GetFuncOrActionType(Type p0, Type p1, Type p2, Type p3, Type p4, Type returnType) =>
 8130            returnType == typeof(void) ? typeof(Action<,,,,>).MakeGenericType(p0, p1, p2, p3, p4) : typeof(Func<,,,,,>).
 8131
 8132        public static Type GetFuncOrActionType(Type p0, Type p1, Type p2, Type p3, Type p4, Type p5, Type returnType) =>
 8133            returnType == typeof(void) ? typeof(Action<,,,,,>).MakeGenericType(p0, p1, p2, p3, p4, p5) : typeof(Func<,,,
 8134
 8135        [RequiresUnreferencedCode(Trimming.Message)]
 8136        public static Type GetFuncOrActionType(Type[] paramTypes, Type returnType)
 8137        {
 8138            if (returnType == typeof(void))
 8139            {
 8140                if (paramTypes.Length == 0)
 8141                    return typeof(Action);
 8142
 8143                return GetAction(paramTypes.Length).MakeGenericType(paramTypes);
 8144            }
 8145
 8146            Type funcType = GetFunc(paramTypes.Length);
 8147            Type[] typeParams = new Type[paramTypes.Length + 1]; // todo: @perf could we Rent the array?
 8148            Array.Copy(paramTypes, typeParams, paramTypes.Length);
 8149            typeParams[paramTypes.Length] = returnType;
 8150            return funcType.MakeGenericType(typeParams);
 8151
 8152            static Type GetAction(int length)
 8153            {
 8154                return length switch
 8155                {
 8156                    1 => typeof(Action<>),
 8157                    2 => typeof(Action<,>),
 8158                    3 => typeof(Action<,,>),
 8159                    4 => typeof(Action<,,,>),
 8160                    5 => typeof(Action<,,,,>),
 8161                    6 => typeof(Action<,,,,,>),
 8162                    7 => typeof(Action<,,,,,,>),
 8163                    8 => typeof(Action<,,,,,,,>),
 8164                    9 => typeof(Action<,,,,,,,,>),
 8165                    10 => typeof(Action<,,,,,,,,,>),
 8166                    11 => typeof(Action<,,,,,,,,,,>),
 8167                    12 => typeof(Action<,,,,,,,,,,,>),
 8168                    13 => typeof(Action<,,,,,,,,,,,,>),
 8169                    14 => typeof(Action<,,,,,,,,,,,,,>),
 8170                    15 => typeof(Action<,,,,,,,,,,,,,,>),
 8171                    16 => typeof(Action<,,,,,,,,,,,,,,,>),
 8172                    _ => throw new NotSupportedException($"Action with so many ({length}) parameters is not supported!")
 8173                };
 8174            }
 8175
 8176            static Type GetFunc(int length)
 8177            {
 8178                return length switch
 8179                {
 8180                    0 => typeof(Func<>),
 8181                    1 => typeof(Func<,>),
 8182                    2 => typeof(Func<,,>),
 8183                    3 => typeof(Func<,,,>),
 8184                    4 => typeof(Func<,,,,>),
 8185                    5 => typeof(Func<,,,,,>),
 8186                    6 => typeof(Func<,,,,,,>),
 8187                    7 => typeof(Func<,,,,,,,>),
 8188                    8 => typeof(Func<,,,,,,,,>),
 8189                    9 => typeof(Func<,,,,,,,,,>),
 8190                    10 => typeof(Func<,,,,,,,,,,>),
 8191                    11 => typeof(Func<,,,,,,,,,,,>),
 8192                    12 => typeof(Func<,,,,,,,,,,,,>),
 8193                    13 => typeof(Func<,,,,,,,,,,,,,>),
 8194                    14 => typeof(Func<,,,,,,,,,,,,,,>),
 8195                    15 => typeof(Func<,,,,,,,,,,,,,,,>),
 8196                    16 => typeof(Func<,,,,,,,,,,,,,,,,>),
 8197                    _ => throw new NotSupportedException($"Func with so many ({length}) parameters is not supported!")
 8198                };
 8199            }
 8200        }
 8201
 8202        public static T GetFirst<T>(this IEnumerable<T> source)
 8203        {
 8204            // This is pretty much Linq.FirstOrDefault except it does not need to check
 8205            // if source is IPartition<T> (but should it?)
 8206
 8207            if (source is IList<T> list)
 8208                return list.Count == 0 ? default : list[0];
 8209            var items = source.GetEnumerator();
 8210            return items.MoveNext() ? items.Current : default;
 8211        }
 8212
 8213        public static T GetFirst<T>(this T[] source) => source.Length == 0 ? default : source[0];
 8214    }
 8215
 8216    [RequiresUnreferencedCode(Trimming.Message)]
 8217    internal static class ILGeneratorTools
 8218    {
 8219        /// <summary>Configuration option to disable the pooling</summary>
 8220        public static bool DisableILGeneratorPooling;
 8221        /// <summary>Configuration option to disable the ILGenerator Emit debug output</summary>
 8222        public static bool DisableDemit;
 8223
 8224#if DEMIT
 8225        [MethodImpl((MethodImplOptions)256)]
 8226        public static void Demit(this ILGenerator il, OpCode opcode, [CallerMemberName] string emitterName = "", [Caller
 8227        {
 8228            il.Emit(opcode);
 8229            if (DisableDemit) return;
 8230            Debug.WriteLine($"{opcode}  -- {emitterName}:{emitterLine}");
 8231        }
 8232
 8233        [MethodImpl((MethodImplOptions)256)]
 8234        public static void Demit(this ILGenerator il, OpCode opcode, Type type, [CallerMemberName] string emitterName = 
 8235        {
 8236            il.Emit(opcode, type);
 8237            if (DisableDemit) return;
 8238            Debug.WriteLine($"{opcode} {type.ToCode(stripNamespace: true)}  -- {emitterName}:{emitterLine}");
 8239        }
 8240
 8241        [MethodImpl((MethodImplOptions)256)]
 8242        public static void Demit(this ILGenerator il, OpCode opcode, FieldInfo value, [CallerMemberName] string emitterN
 8243        {
 8244            il.Emit(opcode, value);
 8245            if (DisableDemit) return;
 8246
 8247            var declType = value.DeclaringType?.ToCode(stripNamespace: true) ?? "";
 8248            var fieldType = value.FieldType.ToCode(stripNamespace: true);
 8249            Debug.WriteLine($"{opcode} {fieldType} {declType}.{value.Name}  -- {emitterName}:{emitterLine}");
 8250        }
 8251
 8252        [MethodImpl((MethodImplOptions)256)]
 8253        public static void Demit(this ILGenerator il, OpCode opcode, MethodInfo value, [CallerMemberName] string emitter
 8254        {
 8255            il.Emit(opcode, value);
 8256            if (DisableDemit) return;
 8257
 8258            var declType = value.DeclaringType?.ToCode(stripNamespace: true) ?? "";
 8259            var retType = value.ReturnType.ToCode(stripNamespace: true);
 8260            var signature = value.ToString();
 8261            var paramStart = signature.IndexOf('(');
 8262            var paramsInParens = paramStart == -1 ? "()" : signature.Substring(paramStart);
 8263            Debug.WriteLine($"{opcode} {retType} {declType}.{value.Name}{paramsInParens}  -- {emitterName}:{emitterLine}
 8264        }
 8265
 8266        [MethodImpl((MethodImplOptions)256)]
 8267        public static void Demit(this ILGenerator il, OpCode opcode, ConstructorInfo value, [CallerMemberName] string em
 8268        {
 8269            il.Emit(opcode, value);
 8270            if (DisableDemit) return;
 8271
 8272            var declType = value.DeclaringType?.ToCode(stripNamespace: true) ?? "";
 8273            var signature = value.ToString();
 8274            var paramStart = signature.IndexOf('(');
 8275            var paramsInParens = paramStart == -1 ? "()" : signature.Substring(paramStart);
 8276            Debug.WriteLine($"{opcode} {declType}{paramsInParens}  -- {emitterName}:{emitterLine}");
 8277        }
 8278
 8279        [MethodImpl((MethodImplOptions)256)]
 8280        public static void Demit(this ILGenerator il, OpCode opcode, Label value,
 8281            [CallerArgumentExpression("value")] string valueName = null, [CallerMemberName] string emitterName = null, [
 8282        {
 8283            il.Emit(opcode, value);
 8284            if (DisableDemit) return;
 8285            Debug.WriteLine($"{opcode} {valueName ?? value.ToString()}  -- {emitterName}:{emitterLine}");
 8286        }
 8287
 8288        [MethodImpl((MethodImplOptions)256)]
 8289        public static void DmarkLabel(this ILGenerator il, Label value,
 8290            [CallerArgumentExpression("value")] string valueName = null, [CallerMemberName] string emitterName = null, [
 8291        {
 8292            il.MarkLabel(value);
 8293            if (DisableDemit) return;
 8294            Debug.WriteLine($"{valueName ?? value.ToString()}  -- {emitterName}:{emitterLine}: ");
 8295        }
 8296
 8297        [MethodImpl((MethodImplOptions)256)]
 8298        public static void Demit(this ILGenerator il, OpCode opcode, byte value, [CallerMemberName] string emitterName =
 8299        {
 8300            il.Emit(opcode, value);
 8301            if (DisableDemit) return;
 8302            Debug.WriteLine($"{opcode} {value}  -- {emitterName}:{emitterLine}");
 8303        }
 8304
 8305        [MethodImpl((MethodImplOptions)256)]
 8306        public static void Demit(this ILGenerator il, OpCode opcode, sbyte value, [CallerMemberName] string emitterName 
 8307        {
 8308            il.Emit(opcode, value);
 8309            if (DisableDemit) return;
 8310            Debug.WriteLine($"{opcode} {value}  -- {emitterName}:{emitterLine}");
 8311        }
 8312
 8313        [MethodImpl((MethodImplOptions)256)]
 8314        public static void Demit(this ILGenerator il, OpCode opcode, short value, [CallerMemberName] string emitterName 
 8315        {
 8316            il.Emit(opcode, value);
 8317            if (DisableDemit) return;
 8318            Debug.WriteLine($"{opcode} {value}  -- {emitterName}:{emitterLine}");
 8319        }
 8320
 8321        [MethodImpl((MethodImplOptions)256)]
 8322        public static void Demit(this ILGenerator il, OpCode opcode, int value, [CallerMemberName] string emitterName = 
 8323        {
 8324            il.Emit(opcode, value);
 8325            if (DisableDemit) return;
 8326            Debug.WriteLine($"{opcode} {value}  -- {emitterName}:{emitterLine}");
 8327        }
 8328
 8329        [MethodImpl((MethodImplOptions)256)]
 8330        public static void Demit(this ILGenerator il, OpCode opcode, long value, [CallerMemberName] string emitterName =
 8331        {
 8332            il.Emit(opcode, value);
 8333            if (DisableDemit) return;
 8334            Debug.WriteLine($"{opcode} {value}  -- {emitterName}:{emitterLine}");
 8335        }
 8336
 8337        [MethodImpl((MethodImplOptions)256)]
 8338        public static void Demit(this ILGenerator il, OpCode opcode, float value, [CallerMemberName] string emitterName 
 8339        {
 8340            il.Emit(opcode, value);
 8341            if (DisableDemit) return;
 8342            Debug.WriteLine($"{opcode} {value}  -- {emitterName}:{emitterLine}");
 8343        }
 8344
 8345        [MethodImpl((MethodImplOptions)256)]
 8346        public static void Demit(this ILGenerator il, OpCode opcode, double value, [CallerMemberName] string emitterName
 8347        {
 8348            il.Emit(opcode, value);
 8349            if (DisableDemit) return;
 8350            Debug.WriteLine($"{opcode} {value}  -- {emitterName}:{emitterLine}");
 8351        }
 8352
 8353        [MethodImpl((MethodImplOptions)256)]
 8354        public static void Demit(this ILGenerator il, string value, OpCode opcode, [CallerMemberName] string emitterName
 8355        {
 8356            il.Emit(opcode, value);
 8357            if (DisableDemit) return;
 8358            Debug.WriteLine($"{opcode} {value}  -- {emitterName}:{emitterLine}");
 8359        }
 8360
 8361#else // not DEMIT :)
 8362
 8363        [MethodImpl((MethodImplOptions)256)]
 8364        public static void Demit(this ILGenerator il, OpCode opcode) => il.Emit(opcode);
 8365
 8366        [MethodImpl((MethodImplOptions)256)]
 8367        public static void Demit(this ILGenerator il, OpCode opcode, Type value) => il.Emit(opcode, value);
 8368
 8369        [MethodImpl((MethodImplOptions)256)]
 8370        public static void Demit(this ILGenerator il, OpCode opcode, FieldInfo value) => il.Emit(opcode, value);
 8371
 8372        [MethodImpl((MethodImplOptions)256)]
 8373        public static void Demit(this ILGenerator il, OpCode opcode, MethodInfo value) => il.Emit(opcode, value);
 8374
 8375        [MethodImpl((MethodImplOptions)256)]
 8376        public static void Demit(this ILGenerator il, OpCode opcode, ConstructorInfo value) => il.Emit(opcode, value);
 8377
 8378        [MethodImpl((MethodImplOptions)256)]
 8379        public static void Demit(this ILGenerator il, OpCode opcode, Label value) => il.Emit(opcode, value);
 8380
 8381        [MethodImpl((MethodImplOptions)256)]
 8382        public static void DmarkLabel(this ILGenerator il, Label value) => il.MarkLabel(value);
 8383
 8384        [MethodImpl((MethodImplOptions)256)]
 8385        public static void Demit(this ILGenerator il, OpCode opcode, byte value) => il.Emit(opcode, value);
 8386
 8387        [MethodImpl((MethodImplOptions)256)]
 8388        public static void Demit(this ILGenerator il, OpCode opcode, sbyte value) => il.Emit(opcode, value);
 8389
 8390        [MethodImpl((MethodImplOptions)256)]
 8391        public static void Demit(this ILGenerator il, OpCode opcode, short value) => il.Emit(opcode, value);
 8392
 8393        [MethodImpl((MethodImplOptions)256)]
 8394        public static void Demit(this ILGenerator il, OpCode opcode, int value) => il.Emit(opcode, value);
 8395
 8396        [MethodImpl((MethodImplOptions)256)]
 8397        public static void Demit(this ILGenerator il, OpCode opcode, long value) => il.Emit(opcode, value);
 8398
 8399        [MethodImpl((MethodImplOptions)256)]
 8400        public static void Demit(this ILGenerator il, OpCode opcode, float value) => il.Emit(opcode, value);
 8401
 8402        [MethodImpl((MethodImplOptions)256)]
 8403        public static void Demit(this ILGenerator il, OpCode opcode, double value) => il.Emit(opcode, value);
 8404
 8405        [MethodImpl((MethodImplOptions)256)]
 8406        public static void Demit(this ILGenerator il, string value, OpCode opcode) => il.Emit(opcode, value);
 8407#endif
 8408    }
 8409
 8410    /// <summary>Reflecting the internal methods to access the more performant for defining the local variable</summary>
 8411    [RequiresUnreferencedCode(Trimming.Message)]
 8412    internal static class DynamicMethodHacks
 8413    {
 8414        [ThreadStatic]
 8415        internal static ILGenerator _pooledILGenerator;
 8416
 8417#if NET6_0_OR_GREATER
 8418        /// <summary>Get new or pool and configure existing DynamicILGenerator</summary>
 8419        [MethodImpl((MethodImplOptions)256)]
 8420        public static ILGenerator RentPooledOrNewILGenerator(DynamicMethod dynMethod, Type returnType, Type[] paramTypes
 8421            // the default ILGenerator size is 64 in .NET 8.0+
 8422            int newStreamSize = 64)
 8423        {
 8424            var reuseILGenerator = DynamicMethodHacks.ReuseDynamicILGenerator;
 8425            if (reuseILGenerator != null)
 8426            {
 8427                var pooledIL = _pooledILGenerator;
 8428                _pooledILGenerator = null;
 8429                if (pooledIL != null)
 8430                {
 8431                    reuseILGenerator(dynMethod, pooledIL, returnType, paramTypes);
 8432                    return pooledIL;
 8433                }
 8434                else
 8435                {
 8436                    Debug.WriteLine("Unexpected: using a New ILGenerator instead of the pooled one");
 8437                }
 8438            }
 8439            return dynMethod.GetILGenerator(newStreamSize);
 8440        }
 8441
 8442        /// <summary>Should be called only after call to DynamicMethod.CreateDelegate</summary>
 8443        [MethodImpl((MethodImplOptions)256)]
 8444        public static void FreePooledILGenerator(DynamicMethod dynMethod, ILGenerator il)
 8445        {
 8446            if (DynamicMethodHacks.ReuseDynamicILGenerator != null)
 8447                _pooledILGenerator = il;
 8448        }
 8449#else
 8450        /// <summary>Get new or pool and configure existing DynamicILGenerator</summary>
 8451        [MethodImpl((MethodImplOptions)256)]
 8452        public static ILGenerator RentPooledOrNewILGenerator(DynamicMethod dynMethod, Type returnType, Type[] paramTypes
 8453            int newStreamSize = 64) =>
 8454            dynMethod.GetILGenerator(newStreamSize);
 8455
 8456        /// <summary>Should be called only after call to DynamicMethod.CreateDelegate</summary>
 8457        [MethodImpl((MethodImplOptions)256)]
 8458        public static void FreePooledILGenerator(DynamicMethod dynMethod, ILGenerator il) { /* do nothing */ }
 8459#endif
 8460
 8461        internal static readonly Func<ILGenerator, Type, int> GetNextLocalVarLocation;
 8462
 8463        internal static int PostInc(ref int i) => i++;
 8464
 8465        internal static Action<DynamicMethod, ILGenerator, Type, Type[]> ReuseDynamicILGenerator;
 8466
 8467
 8468        [ThreadStatic]
 8469        internal static SignatureHelper _pooledSignatureHelper;
 8470
 8471
 8472        internal static FieldInfo ILGeneratorField;
 8473        internal static Type DynamicILGeneratorType;
 8474
 8475        static DynamicMethodHacks()
 8476        {
 8477            const BindingFlags instanceNonPublic = BindingFlags.Instance | BindingFlags.NonPublic;
 8478            const BindingFlags instancePublic = BindingFlags.Instance | BindingFlags.Public;
 8479            const BindingFlags staticNonPublic = BindingFlags.Static | BindingFlags.NonPublic;
 8480            const BindingFlags staticPublic = BindingFlags.Static | BindingFlags.Public;
 8481
 8482            ILGeneratorField = typeof(DynamicMethod).GetField("_ilGenerator", instanceNonPublic);
 8483            if (ILGeneratorField == null)
 8484                return; // nothing to do here
 8485
 8486            DynamicILGeneratorType = ILGeneratorField.FieldType;
 8487
 8488            // Avoid demit polluting the output of the the initialization phase
 8489            var prevDemitValue = ILGeneratorTools.DisableDemit;
 8490            ILGeneratorTools.DisableDemit = true;
 8491
 8492            if (!ILGeneratorTools.DisableILGeneratorPooling)
 8493            {
 8494                // ## 1. Reuse the DynamicILGenerator
 8495                //
 8496                // Reference code - NET. v8, v9:
 8497                /*
 8498                    public ILGenerator GetILGenerator(int streamSize)
 8499                    {
 8500                        if (_ilGenerator == null)
 8501                        {
 8502                            byte[] methodSignature = SignatureHelper.GetMethodSigHelper(
 8503                                null, CallingConvention, ReturnType, null, null, _parameterTypes, null, null).GetSignatu
 8504                            _ilGenerator = new DynamicILGenerator(this, methodSignature, streamSize);
 8505                        }
 8506                        return _ilGenerator;
 8507                    }
 8508
 8509                    internal sealed class DynamicScope
 8510                    {
 8511                        internal readonly List<object?> m_tokens = new List<object?> { null };
 8512                        public int GetTokenFor(byte[] signature)
 8513                        {
 8514                            m_tokens.Add(signature);
 8515                            return m_tokens.Count - 1 | (int)MetadataTokenType.Signature;
 8516                        }
 8517                    }
 8518
 8519                    internal DynamicScope m_scope;
 8520                    private readonly int m_methodSigToken;
 8521
 8522                    public DynamicILGenerator(
 8523                        DynamicMethod method,
 8524                        byte[] methodSignature,
 8525                        int streamSize)
 8526                    {
 8527                        m_scope = new DynamicScope();
 8528                        m_methodSigToken = m_scope.GetTokenFor(methodSignature);
 8529
 8530                        m_ScopeTree = new ScopeTree();
 8531                        m_ILStream = new byte[Math.Max(size, DefaultSize)];
 8532
 8533                        m_localSignature = SignatureHelper.GetLocalVarSigHelper((method as RuntimeMethodBuilder)?.GetTyp
 8534                        m_methodBuilder = method; // set to the new DynamicMethod
 8535                    }
 8536                */
 8537                var m_ScopeTreeField = DynamicILGeneratorType.GetField("m_ScopeTree", instanceNonPublic);
 8538                if (m_ScopeTreeField == null)
 8539                    goto endOfReuse;
 8540
 8541                var ScopeTreeCtor = m_ScopeTreeField.FieldType.GetConstructor(instanceNonPublic, null, Type.EmptyTypes, 
 8542                if (ScopeTreeCtor == null)
 8543                    goto endOfReuse;
 8544
 8545                var DynamicILGeneratorScopeField = DynamicILGeneratorType.GetField("m_scope", instanceNonPublic);
 8546                if (DynamicILGeneratorScopeField == null)
 8547                    goto endOfReuse;
 8548
 8549                var DynamicILGeneratorScopeType = DynamicILGeneratorScopeField.FieldType;
 8550                var DynamicScopeTokensField = DynamicILGeneratorScopeType.GetField("m_tokens", instanceNonPublic);
 8551                if (DynamicScopeTokensField == null)
 8552                    goto endOfReuse;
 8553
 8554                var DynamicScopeTokensItem = DynamicScopeTokensField.FieldType.GetProperty("Item");
 8555                Debug.Assert(DynamicScopeTokensItem != null, "DynamicScopeTokens.Item should not be null");
 8556
 8557                var getMethodSigHelperParams = ExpressionCompiler.RentPooledOrNewParamTypes(typeof(Module), typeof(Type)
 8558                var GetMethodSigHelperMethod = typeof(SignatureHelper).GetMethod("GetMethodSigHelper", staticPublic, nul
 8559                ExpressionCompiler.FreePooledParamTypes(getMethodSigHelperParams);
 8560                if (GetMethodSigHelperMethod == null)
 8561                    goto endOfReuse;
 8562
 8563                var GetLocalVarSigHelperMethod = typeof(SignatureHelper).GetMethod("GetLocalVarSigHelper", staticPublic,
 8564                if (GetLocalVarSigHelperMethod == null)
 8565                    goto endOfReuse;
 8566
 8567                var getSignatureParams = ExpressionCompiler.RentPooledOrNewParamTypes(typeof(bool));
 8568                var SignatureHelper_GetSignatureMethod = typeof(SignatureHelper).GetMethod("GetSignature", instanceNonPu
 8569                ExpressionCompiler.FreePooledParamTypes(getSignatureParams);
 8570                if (SignatureHelper_GetSignatureMethod == null)
 8571                    goto endOfReuse;
 8572
 8573                var getTokenForParams = ExpressionCompiler.RentPooledOrNewParamTypes(typeof(byte[]));
 8574                var GetTokenForMethod = DynamicILGeneratorScopeType.GetMethod("GetTokenFor", instancePublic, null, getTo
 8575                ExpressionCompiler.FreePooledParamTypes(getTokenForParams);
 8576                if (GetTokenForMethod == null)
 8577                    goto endOfReuse;
 8578
 8579                var MethodSigTokenField = DynamicILGeneratorType.GetField("m_methodSigToken", instanceNonPublic);
 8580                if (MethodSigTokenField == null)
 8581                    goto endOfReuse;
 8582
 8583                var dynMethodParamTypes = ExpressionCompiler.RentPooledOrNewParamTypes(
 8584                        typeof(ExpressionCompiler.ArrayClosure), typeof(DynamicMethod), typeof(ILGenerator), typeof(Type
 8585
 8586                var dynMethod = new DynamicMethod(string.Empty, typeof(void), dynMethodParamTypes, typeof(ExpressionComp
 8587
 8588                var il = dynMethod.GetILGenerator(512); // precalculated size to avoid waste
 8589
 8590                var baseFields = DynamicILGeneratorType.BaseType.GetFields(BindingFlags.Instance | BindingFlags.Public |
 8591                foreach (var field in baseFields)
 8592                {
 8593                    var fieldName = field.Name;
 8594                    if (fieldName == "m_localSignature")
 8595                    {
 8596                        il.Demit(OpCodes.Ldarg_2);
 8597                        il.Demit(OpCodes.Call, GetLocalVarSigHelperMethod);
 8598                        il.Demit(OpCodes.Stfld, field);
 8599                        continue;
 8600                    }
 8601
 8602                    // m_ScopeTree = new ScopeTree();
 8603                    if (fieldName == "m_ScopeTree")
 8604                    {
 8605                        il.Demit(OpCodes.Ldarg_2);
 8606                        il.Demit(OpCodes.Newobj, ScopeTreeCtor);
 8607                        il.Demit(OpCodes.Stfld, field);
 8608                        continue;
 8609                    }
 8610
 8611                    // m_methodBuilder = method; // dynamicMethod
 8612                    if (fieldName == "m_methodBuilder")
 8613                    {
 8614                        il.Demit(OpCodes.Ldarg_2);
 8615                        il.Demit(OpCodes.Ldarg_1);
 8616                        il.Demit(OpCodes.Stfld, field);
 8617                        continue;
 8618                    }
 8619
 8620                    if (fieldName == "m_ILStream")
 8621                        continue; // reuse the previous il stream
 8622
 8623                    il.Demit(OpCodes.Ldarg_2);
 8624                    ExpressionCompiler.EmittingVisitor.EmitDefault(il, field.FieldType);
 8625                    il.Demit(OpCodes.Stfld, field);
 8626                }
 8627
 8628                // var scope = new DynamicScope();
 8629                var dynamicScopeCtor = DynamicILGeneratorScopeType.GetConstructor(Type.EmptyTypes);
 8630                if (dynamicScopeCtor == null)
 8631                    goto endOfReuse;
 8632                il.Emit(OpCodes.Newobj, dynamicScopeCtor);
 8633                var scopeVar = il.DeclareLocal(DynamicILGeneratorScopeType).LocalIndex;
 8634                ExpressionCompiler.EmittingVisitor.EmitStoreLocalVariable(il, scopeVar);
 8635
 8636                /*
 8637                    private byte[] m_signature; // todo: @perf keep it, because it would be copied anyway
 8638                    private int m_currSig; // index into m_signature buffer for next available byte
 8639                    private int m_sizeLoc; // index into m_signature buffer to put m_argCount (will be NO_SIZE_IN_SIG if
 8640                    private ModuleBuilder? m_module;
 8641                    private bool m_sigDone;
 8642                    private int m_argCount; // tracking number of arguments in the signature
 8643
 8644                    internal static SignatureHelper GetMethodSigHelper(
 8645                        Module? scope, CallingConventions callingConvention, int cGenericParam,
 8646                        Type? returnType, Type[]? requiredReturnTypeCustomModifiers, Type[]? optionalReturnTypeCustomMod
 8647                        Type[]? parameterTypes, Type[][]? requiredParameterTypeCustomModifiers, Type[][]? optionalParame
 8648                    {
 8649                        SignatureHelper sigHelp;
 8650                        MdSigCallingConvention intCall;
 8651
 8652                        // not needed, always provided
 8653                        returnType ??= typeof(void);
 8654
 8655                        // not needed, always CallingConventions.Standard
 8656                        intCall = MdSigCallingConvention.Default;
 8657                        if ((callingConvention & CallingConventions.VarArgs) == CallingConventions.VarArgs)
 8658                            intCall = MdSigCallingConvention.Vararg;
 8659
 8660                        // not needed, always 0
 8661                        if (cGenericParam > 0)
 8662                        {
 8663                            intCall |= MdSigCallingConvention.Generic;
 8664                        }
 8665
 8666                        // not needed, can be externalized as a const, precalculate the `unchecked((byte)CallingConventi
 8667                        const byte Mask = (byte)(CallingConventions.HasThis | CallingConventions.ExplicitThis);
 8668                        intCall = (MdSigCallingConvention)((byte)intCall | (unchecked((byte)callingConvention) & Mask));
 8669
 8670                        sigHelp = new SignatureHelper(scope, intCall, cGenericParam, returnType,
 8671                            requiredReturnTypeCustomModifiers, optionalReturnTypeCustomModifiers);
 8672
 8673                        // m_signature = new byte[32];
 8674                        // m_currSig = 0;
 8675                        // m_module = mod as ModuleBuilder;
 8676                        // m_argCount = 0;
 8677                        // m_sigDone = false;
 8678                        // m_sizeLoc = NO_SIZE_IN_SIG;
 8679
 8680                        sigHelp.AddArguments(parameterTypes, requiredParameterTypeCustomModifiers, optionalParameterType
 8681
 8682                        return sigHelp;
 8683                    }
 8684                */
 8685                // pseudo code to reuse the pooled SignatureHelper
 8686                /*
 8687                var signatureHelper = _pooledSignatureHelper;
 8688                _pooledSignatureHelper = null;
 8689                if (signatureHelper == null)
 8690                    signatureBytes = SignatureHelper.GetMethodSigHelper(null, returnType, paramTypes).GetSignature(true)
 8691                else
 8692                {
 8693                    // no need to set, can reuse the previous value
 8694                    // m_signature = new byte[32];
 8695                    // signatureHelper.m_module = null;
 8696                    signatureHelper.m_currSig = 0;
 8697                    signatureHelper.m_argCount = 0;
 8698                    signatureHelper.m_sigDone = false;
 8699                    signatureHelper.m_sizeLoc = -1;
 8700                    signatureHelper.AddOneArgTypeHelper(returnType, null, null);
 8701                    signatureHelper.AddArguments(paramTypes, null, null);
 8702
 8703                    var signatureBytes = signatureHelper.GetSignature(true);
 8704                    _pooledSignatureHelper = signatureHelper;
 8705                }
 8706                */
 8707                var sigBytesVar = il.DeclareLocal(typeof(byte[])).LocalIndex;
 8708
 8709                var pooledSignatureHelperField = typeof(DynamicMethodHacks).GetField(nameof(_pooledSignatureHelper), sta
 8710                Debug.Assert(pooledSignatureHelperField != null, "_pooledSignatureHelper field not found!");
 8711
 8712                il.Emit(OpCodes.Ldsfld, pooledSignatureHelperField);
 8713                var sigHelperVar = il.DeclareLocal(typeof(SignatureHelper)).LocalIndex;
 8714                ExpressionCompiler.EmittingVisitor.EmitStoreAndLoadLocalVariable(il, sigHelperVar); // loading it here t
 8715                il.Emit(OpCodes.Ldnull); // set the pooled instance to null
 8716                il.Emit(OpCodes.Stsfld, pooledSignatureHelperField);
 8717
 8718                var labelSigHelperNull = il.DefineLabel();
 8719                il.Emit(OpCodes.Brfalse, labelSigHelperNull);
 8720
 8721                // signatureHelper.m_currSig = 0
 8722                ExpressionCompiler.EmittingVisitor.EmitLoadLocalVariable(il, sigHelperVar);
 8723                il.Emit(OpCodes.Ldc_I4_0);
 8724                var m_currSig = typeof(SignatureHelper).GetField("m_currSig", instanceNonPublic);
 8725                if (m_currSig == null)
 8726                    goto endOfReuse;
 8727                il.Emit(OpCodes.Stfld, m_currSig);
 8728
 8729                //signatureHelper.m_argCount = 0;
 8730                ExpressionCompiler.EmittingVisitor.EmitLoadLocalVariable(il, sigHelperVar);
 8731                il.Emit(OpCodes.Ldc_I4_0);
 8732                var m_argCount = typeof(SignatureHelper).GetField("m_argCount", instanceNonPublic);
 8733                if (m_argCount == null)
 8734                    goto endOfReuse;
 8735                il.Emit(OpCodes.Stfld, m_argCount);
 8736
 8737                // signatureHelper.m_sigDone = false;
 8738                ExpressionCompiler.EmittingVisitor.EmitLoadLocalVariable(il, sigHelperVar);
 8739                il.Emit(OpCodes.Ldc_I4_0);
 8740                var m_sigDone = typeof(SignatureHelper).GetField("m_sigDone", instanceNonPublic);
 8741                if (m_sigDone == null)
 8742                    goto endOfReuse;
 8743                il.Emit(OpCodes.Stfld, m_sigDone);
 8744
 8745                // signatureHelper.m_sizeLoc = -1;
 8746                ExpressionCompiler.EmittingVisitor.EmitLoadLocalVariable(il, sigHelperVar);
 8747                il.Emit(OpCodes.Ldc_I4_M1);
 8748                var m_sizeLoc = typeof(SignatureHelper).GetField("m_sizeLoc", instanceNonPublic);
 8749                if (m_sizeLoc == null)
 8750                    goto endOfReuse;
 8751                il.Emit(OpCodes.Stfld, m_sizeLoc);
 8752
 8753                // signatureHelper.AddOneArgTypeHelper(returnType, null, null);
 8754                ExpressionCompiler.EmittingVisitor.EmitLoadLocalVariable(il, sigHelperVar);
 8755                il.Emit(OpCodes.Ldarg_3); // load return type
 8756                il.Emit(OpCodes.Ldnull); // load required return type custom modifiers
 8757                il.Emit(OpCodes.Ldnull); // load optional return type custom modifiers
 8758                var addOneArgTypeHelperParams = ExpressionCompiler.RentPooledOrNewParamTypes(typeof(Type), typeof(Type[]
 8759                var AddOneArgTypeHelperMethod = typeof(SignatureHelper).GetMethod("AddOneArgTypeHelper", instanceNonPubl
 8760                ExpressionCompiler.FreePooledParamTypes(addOneArgTypeHelperParams);
 8761                if (AddOneArgTypeHelperMethod == null)
 8762                    goto endOfReuse;
 8763                il.Emit(OpCodes.Call, AddOneArgTypeHelperMethod);
 8764
 8765                // signatureHelper.AddArguments(paramTypes, null, null);
 8766                ExpressionCompiler.EmittingVisitor.EmitLoadLocalVariable(il, sigHelperVar);
 8767                il.Emit(OpCodes.Ldarg_S, 4); // load parameter types arrays
 8768                il.Emit(OpCodes.Ldnull); // load required parameter type custom modifiers
 8769                il.Emit(OpCodes.Ldnull); // load optional parameter type custom modifiers
 8770
 8771                var addArgumentsParams = ExpressionCompiler.RentPooledOrNewParamTypes(typeof(Type[]), typeof(Type[][]), 
 8772                var AddArgumentsMethod = typeof(SignatureHelper).GetMethod("AddArguments", instancePublic, null, addArgu
 8773                ExpressionCompiler.FreePooledParamTypes(addArgumentsParams);
 8774                if (AddArgumentsMethod == null)
 8775                    goto endOfReuse;
 8776                il.Emit(OpCodes.Call, AddArgumentsMethod);
 8777
 8778                // signatureBytes = signatureHelper.GetSignature(true);
 8779                ExpressionCompiler.EmittingVisitor.EmitLoadLocalVariable(il, sigHelperVar);
 8780                il.Emit(OpCodes.Ldc_I4_1); // load true
 8781                il.Emit(OpCodes.Call, SignatureHelper_GetSignatureMethod);
 8782                ExpressionCompiler.EmittingVisitor.EmitStoreLocalVariable(il, sigBytesVar);
 8783
 8784                // free the signature helper to the pool
 8785                ExpressionCompiler.EmittingVisitor.EmitLoadLocalVariable(il, sigHelperVar);
 8786                il.Emit(OpCodes.Stsfld, pooledSignatureHelperField);
 8787
 8788                // done
 8789                var labelSigHelperDone = il.DefineLabel();
 8790                il.Emit(OpCodes.Br, labelSigHelperDone);
 8791
 8792                // Standard handling:
 8793                // signatureBytes = SignatureHelper.GetMethodSigHelper(null, returnType, paramTypes).GetSignature(true);
 8794                il.MarkLabel(labelSigHelperNull);
 8795
 8796                il.Emit(OpCodes.Ldnull); // for the module
 8797                il.Emit(OpCodes.Ldarg_3); // load return type
 8798                il.Emit(OpCodes.Ldarg_S, 4); // load parameter types arrays
 8799                il.Emit(OpCodes.Call, GetMethodSigHelperMethod);
 8800                il.Emit(OpCodes.Ldc_I4_1); // load true
 8801                il.Emit(OpCodes.Call, SignatureHelper_GetSignatureMethod);
 8802                ExpressionCompiler.EmittingVisitor.EmitStoreLocalVariable(il, sigBytesVar);
 8803
 8804                // todo: @perf GetSignature(true) will copy internal byte buffer almost always, see
 8805                /*
 8806                    internal byte[] GetSignature(bool appendEndOfSig)
 8807                    {
 8808                        // Chops the internal signature to the appropriate length.  Adds the
 8809                        // end token to the signature and marks the signature as finished so that
 8810                        // no further tokens can be added. Return the full signature in a trimmed array.
 8811                        if (!m_sigDone)
 8812                        {
 8813                            if (appendEndOfSig)
 8814                                AddElementType(CorElementType.ELEMENT_TYPE_END);
 8815                            SetNumberOfSignatureElements(true);
 8816                            m_sigDone = true;
 8817                        }
 8818
 8819                        // This case will only happen if the user got the signature through
 8820                        // InternalGetSignature first and then called GetSignature.
 8821                        if (m_signature.Length > m_currSig)
 8822                        {
 8823                            byte[] temp = new byte[m_currSig];
 8824                            Array.Copy(m_signature, temp, m_currSig);
 8825                            m_signature = temp;
 8826                        }
 8827
 8828                        return m_signature;
 8829                    }
 8830                */
 8831
 8832                il.MarkLabel(labelSigHelperDone);
 8833
 8834                // m_methodSigToken = scope.GetTokenFor(methodSignature);
 8835                il.Emit(OpCodes.Ldarg_2);
 8836                ExpressionCompiler.EmittingVisitor.EmitLoadLocalVariable(il, scopeVar);
 8837                ExpressionCompiler.EmittingVisitor.EmitLoadLocalVariable(il, sigBytesVar);
 8838                il.Emit(OpCodes.Call, GetTokenForMethod);
 8839                il.Emit(OpCodes.Stfld, MethodSigTokenField);
 8840
 8841                // m_scope = scope;
 8842                il.Emit(OpCodes.Ldarg_2);
 8843                ExpressionCompiler.EmittingVisitor.EmitLoadLocalVariable(il, scopeVar);
 8844                il.Emit(OpCodes.Stfld, DynamicILGeneratorScopeField);
 8845
 8846                // store the reused ILGenerator to
 8847                il.Emit(OpCodes.Ldarg_1);
 8848                il.Emit(OpCodes.Ldarg_2);
 8849                il.Emit(OpCodes.Stfld, ILGeneratorField);
 8850
 8851                il.Emit(OpCodes.Ret);
 8852
 8853                ReuseDynamicILGenerator = (Action<DynamicMethod, ILGenerator, Type, Type[]>)
 8854                    dynMethod.CreateDelegate(typeof(Action<DynamicMethod, ILGenerator, Type, Type[]>), ExpressionCompile
 8855
 8856                // Put the first used ILGenerator into the pool, let's not waste it from te get go
 8857                _pooledILGenerator = il;
 8858
 8859                ExpressionCompiler.FreePooledParamTypes(dynMethodParamTypes);
 8860            endOfReuse:;
 8861            }
 8862            {
 8863                // ## 2. Get Next Local Variable Index/Location
 8864
 8865                // The original ILGenerator methods we are trying to hack without allocating the `LocalBuilder`
 8866                /*
 8867                public virtual LocalBuilder DeclareLocal(Type localType)
 8868                {
 8869                    return this.DeclareLocal(localType, false);
 8870                }
 8871
 8872                public virtual LocalBuilder DeclareLocal(Type localType, bool pinned)
 8873                {
 8874                    MethodBuilder methodBuilder = this.m_methodBuilder as MethodBuilder;
 8875                    if ((MethodInfo)methodBuilder == (MethodInfo)null)
 8876                        throw new NotSupportedException();
 8877                    if (methodBuilder.IsTypeCreated())
 8878                        throw new InvalidOperationException(SR.InvalidOperation_TypeHasBeenCreated);
 8879                    if (localType == (Type)null)
 8880                        throw new ArgumentNullException(nameof(localType));
 8881                    if (methodBuilder.m_bIsBaked)
 8882                        throw new InvalidOperationException(SR.InvalidOperation_MethodBaked);
 8883                    this.m_localSignature.AddArgument(localType, pinned);
 8884                    LocalBuilder localBuilder = new LocalBuilder(this.m_localCount, localType, (MethodInfo)methodBuilder
 8885                    ++this.m_localCount;
 8886                    return localBuilder;
 8887                }
 8888                */
 8889                // Let's try to acquire the more efficient less allocating method
 8890                var m_localSignatureField = DynamicILGeneratorType.GetField("m_localSignature", instanceNonPublic);
 8891                if (m_localSignatureField == null)
 8892                    goto endOfGetNextVar;
 8893
 8894                var m_localCountField = DynamicILGeneratorType.GetField("m_localCount", instanceNonPublic);
 8895                if (m_localCountField == null)
 8896                    goto endOfGetNextVar;
 8897
 8898                // looking for the `SignatureHelper.AddArgument(Type argument, bool pinned)`
 8899                var typeAndBoolParamTypes = ExpressionCompiler.RentPooledOrNewParamTypes(typeof(Type), typeof(bool));
 8900                var SignatureHelper_AddArgumentMethod = typeof(SignatureHelper).GetMethod("AddArgument", typeAndBoolPara
 8901                ExpressionCompiler.FreePooledParamTypes(typeAndBoolParamTypes);
 8902                if (SignatureHelper_AddArgumentMethod == null)
 8903                    goto endOfGetNextVar;
 8904
 8905                // our own helper - always available
 8906                var postIncMethod = typeof(DynamicMethodHacks).GetMethod(nameof(PostInc), staticNonPublic);
 8907                Debug.Assert(postIncMethod != null, "PostInc method not found!");
 8908
 8909                var paramTypes = ExpressionCompiler.RentPooledOrNewParamTypes(typeof(ExpressionCompiler.ArrayClosure), t
 8910                var dynMethod = new DynamicMethod(string.Empty, typeof(int), paramTypes, typeof(ExpressionCompiler.Array
 8911
 8912                // it does not use the pooled il generator here, to isolate this variable hack from the il generator poo
 8913                var il = dynMethod.GetILGenerator(32);
 8914
 8915                // emitting `il.m_localSignature.AddArgument(type);`
 8916                il.Emit(OpCodes.Ldarg_1);  // load `il` argument (arg_0 is the empty closure object)
 8917                il.Emit(OpCodes.Ldfld, m_localSignatureField);
 8918                il.Emit(OpCodes.Ldarg_2);  // load `type` argument
 8919                il.Emit(OpCodes.Ldc_I4_0); // load `pinned: false` argument
 8920                il.Emit(OpCodes.Call, SignatureHelper_AddArgumentMethod);
 8921
 8922                // emitting `return PostInc(ref il.LocalCount);`
 8923                il.Emit(OpCodes.Ldarg_1); // load `il` argument
 8924                il.Emit(OpCodes.Ldflda, m_localCountField);
 8925                il.Emit(OpCodes.Call, postIncMethod);
 8926
 8927                il.Emit(OpCodes.Ret);
 8928
 8929                GetNextLocalVarLocation = (Func<ILGenerator, Type, int>)
 8930                    dynMethod.CreateDelegate(typeof(Func<ILGenerator, Type, int>), ExpressionCompiler.EmptyArrayClosure)
 8931
 8932                ExpressionCompiler.FreePooledParamTypes(paramTypes);
 8933            endOfGetNextVar:;
 8934            }
 8935
 8936            // Restore the demit
 8937            ILGeneratorTools.DisableDemit = prevDemitValue;
 8938
 8939            // ## 3 TBD
 8940            //
 8941            // todo: @perf do batch Emit by manually calling `EnsureCapacity` once then `InternalEmit` multiple times
 8942            // todo: @perf Replace the `Emit(opcode, int)` with the more specialized `Emit(opcode)`, `Emit(opcode, byte)
 8943            // avoiding internal check for Ldc_I4, Ldarg, Ldarga, Starg then call `PutInteger4` only if needed see https
 8944            // var ensureCapacityMethod = ilGenTypeInfo.GetDeclaredMethod("EnsureCapacity");
 8945            // var internalEmitMethod   = ilGenTypeInfo.GetDeclaredMethod("InternalEmit");
 8946            // var putInteger4Method    = ilGenTypeInfo.GetDeclaredMethod("PutInteger4");
 8947        }
 8948
 8949
 8950#if DEBUG_INFO_LOCAL_VARIABLE_USAGE
 8951        [ThreadStatic]
 8952        public static SmallMap8<Type, int, RefEq<Type>> LocalVarUsage;
 8953#endif
 8954        // todo: @perf add the map of the used local variables that can be reused, e.g. we are getting the variable used
 8955        /// <summary>Efficiently returns the next variable index, hopefully without unnecessary allocations.</summary>
 8956        [MethodImpl((MethodImplOptions)256)]
 8957        public static int GetNextLocalVarIndex(this ILGenerator il, Type t)
 8958        {
 8959#if DEBUG_INFO_LOCAL_VARIABLE_USAGE
 8960            try
 8961            {
 8962                ref var varUsage = ref LocalVarUsage.Map.AddOrGetValueRef(t, out var found);
 8963                if (!found)
 8964                    varUsage = 1;
 8965                else
 8966                    ++varUsage;
 8967            }
 8968            catch (Exception ex)
 8969            {
 8970                Debug.WriteLine("Error tracking the local variable usage: " + ex);
 8971            }
 8972#endif
 8973            return GetNextLocalVarLocation?.Invoke(il, t) ?? il.DeclareLocal(t).LocalIndex;
 8974        }
 8975
 8976        // todo: @perf add MultiOpCodes emit to save on the EnsureCapacity calls
 8977        // todo: @perf create EmitMethod without additional GetParameters call
 8978        /*
 8979        // original code:
 8980        public override void Emit(OpCode opcode, MethodInfo meth)
 8981        {
 8982            ArgumentNullException.ThrowIfNull(meth);
 8983
 8984            int stackchange = 0;
 8985            int token;
 8986            DynamicMethod? dynMeth = meth as DynamicMethod;
 8987            if (dynMeth == null)
 8988            {
 8989                RuntimeMethodInfo? rtMeth = meth as RuntimeMethodInfo;
 8990                if (rtMeth == null)
 8991                    throw new ArgumentException(SR.Argument_MustBeRuntimeMethodInfo, nameof(meth));
 8992
 8993                RuntimeType declaringType = rtMeth.GetRuntimeType();
 8994                if (declaringType != null && (declaringType.IsGenericType || declaringType.IsArray))
 8995                    token = GetTokenFor(rtMeth, declaringType);
 8996                else
 8997                    token = GetTokenFor(rtMeth);
 8998            }
 8999            else
 9000            {
 9001                // rule out not allowed operations on DynamicMethods
 9002                if (opcode.Equals(OpCodes.Ldtoken) || opcode.Equals(OpCodes.Ldftn) || opcode.Equals(OpCodes.Ldvirtftn))
 9003                {
 9004                    throw new ArgumentException(SR.Argument_InvalidOpCodeOnDynamicMethod);
 9005                }
 9006                token = GetTokenFor(dynMeth);
 9007            }
 9008
 9009            EnsureCapacity(7);
 9010            InternalEmit(opcode);
 9011
 9012            if (opcode.StackBehaviourPush == StackBehaviour.Varpush
 9013                && meth.ReturnType != typeof(void))
 9014            {
 9015                stackchange++;
 9016            }
 9017            if (opcode.StackBehaviourPop == StackBehaviour.Varpop)
 9018            {
 9019                stackchange -= meth.GetParametersNoCopy().Length;
 9020            }
 9021            // Pop the "this" parameter if the method is non-static,
 9022            //  and the instruction is not newobj/ldtoken/ldftn.
 9023            if (!meth.IsStatic &&
 9024                !(opcode.Equals(OpCodes.Newobj) || opcode.Equals(OpCodes.Ldtoken) || opcode.Equals(OpCodes.Ldftn)))
 9025            {
 9026                stackchange--;
 9027            }
 9028
 9029            UpdateStackSize(opcode, stackchange);
 9030            PutInteger4(token);
 9031        }
 9032
 9033        // stripped down code for not generic method and not array method:
 9034        public override void Emit(OpCode opcode, MethodInfo meth, int paramCount)
 9035        {
 9036            m_scope.m_tokens.Add(((RuntimeMethodInfo)meth).MethodHandle);
 9037            var token = m_scope.m_tokens.Count - 1 | (int)MetadataTokenType.MethodDef; // MethodDef is 0x06000000
 9038
 9039            // Guarantees an array capable of holding at least size elements.
 9040            if (m_length + size >= m_ILStream.Length)
 9041                IncreaseCapacity(7);
 9042
 9043            m_ILStream[m_length++] = (byte)opcode.Value;
 9044            UpdateStackSize(opcode, 0);
 9045
 9046            int stackchange = 0;
 9047            if (meth.ReturnType != typeof(void))
 9048                stackchange++;
 9049            stackchange -= paramCount;
 9050            if (!meth.IsStatic)
 9051                stackchange--;
 9052
 9053            UpdateStackSize(opcode, stackchange);
 9054
 9055            BinaryPrimitives.WriteInt32LittleEndian(m_ILStream.AsSpan(m_length), token);
 9056            m_length += 4;
 9057        }
 9058        */
 9059    }
 9060
 9061    [RequiresUnreferencedCode(Trimming.Message)]
 9062    internal static class ToExpressionPrinter
 9063    {
 9064        /// <summary>
 9065        /// Prints the expression in its constructing syntax -
 9066        /// helpful to get the expression from the debug session and put into it the code for the test.
 9067        /// </summary>
 9068        public static string ToExpressionString(this Expression expr, ObjectToCode notRecognizedToCode = null) =>
 9069            expr.ToExpressionString(out var _, out var _, out var _, notRecognizedToCode: notRecognizedToCode);
 9070
 9071        // todo: @api There should be a version returning StringBuilder the same as for ToCSharpString
 9072        /// <summary>
 9073        /// Prints the expression in its constructing syntax -
 9074        /// helpful to get the expression from the debug session and put into it the code for the test.
 9075        /// In addition, returns the gathered expressions, parameters ad labels.
 9076        /// </summary>
 9077        public static string ToExpressionString(this Expression expr,
 9078            out List<ParameterExpression> paramsExprs, out List<Expression> uniqueExprs, out List<LabelTarget> lts,
 9079            bool stripNamespace = false, Func<Type, string, string> printType = null, int indentSpaces = 2, ObjectToCode
 9080        {
 9081            var sb = new StringBuilder(1024);
 9082            sb.Append("var expr = ");
 9083            paramsExprs = new List<ParameterExpression>();
 9084            uniqueExprs = new List<Expression>();
 9085            lts = new List<LabelTarget>();
 9086            sb = expr.CreateExpressionString(sb, paramsExprs, uniqueExprs, lts, 2, stripNamespace, printType, indentSpac
 9087
 9088            if (lts.Count > 0)
 9089                sb.Insert(0, $"var l = new LabelTarget[{lts.Count}]; // the labels{NewLine}");
 9090            if (uniqueExprs.Count > 0)
 9091                sb.Insert(0, $"var e = new Expression[{uniqueExprs.Count}]; // the unique expressions{NewLine}");
 9092            if (paramsExprs.Count > 0)
 9093                sb.Insert(0, $"var p = new ParameterExpression[{paramsExprs.Count}]; // the parameter expressions{NewLin
 9094
 9095            return sb.ToString();
 9096        }
 9097
 9098        // Searches first for the expression reference in the `uniqueExprs` and adds the reference to expression by inde
 9099        // otherwise delegates to `CreateExpressionCodeString`
 9100        internal static StringBuilder ToExpressionString(this Expression expr, StringBuilder sb,
 9101            List<ParameterExpression> paramsExprs, List<Expression> uniqueExprs, List<LabelTarget> lts,
 9102            int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode no
 9103        {
 9104            if (expr is ParameterExpression p)
 9105                return p.ToExpressionString(sb, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType, in
 9106
 9107            if (uniqueExprs.TryGetIndex(out var i, expr, uniqueExprs.Count, default(RefEq<Expression>)))
 9108                return sb.Append("e[").Append(i)
 9109                    // output expression type and kind to help to understand what is it
 9110                    .Append(" // ").Append(expr.NodeType.ToString()).Append(" of ")
 9111                    .Append(expr.Type.ToCode(stripNamespace, printType))
 9112                    .NewLineIndent(lineIndent).Append("]");
 9113
 9114            uniqueExprs.Add(expr);
 9115            sb.Append("e[").Append(uniqueExprs.Count - 1).Append("]=");
 9116            return expr.CreateExpressionString(sb, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType,
 9117        }
 9118
 9119        internal static StringBuilder ToExpressionString(this ParameterExpression pe, StringBuilder sb,
 9120            List<ParameterExpression> paramsExprs, List<Expression> uniqueExprs, List<LabelTarget> lts,
 9121            int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode no
 9122        {
 9123            if (paramsExprs.TryGetIndex(out var i, pe, paramsExprs.Count, default(RefEq<PE>)))
 9124            {
 9125                SmallList<NamedWithIndex, Stack4<NamedWithIndex>> named = default;
 9126                return sb
 9127                    .Append("p[").Append(i)
 9128                    .Append(" // (")
 9129                    .Append(!pe.Type.IsPrimitive && pe.Type.IsValueType ? "[struct] " : string.Empty)
 9130                    .Append(pe.Type.ToCode(stripNamespace, printType))
 9131                    .Append(' ')
 9132                    .AppendName(pe, pe.Name, pe.Type.ToCode(stripNamespace, printType), ref named, pe.GetHashCode()).App
 9133                    .NewLineIndent(lineIndent)
 9134                    .Append(']');
 9135            }
 9136            paramsExprs.Add(pe);
 9137            sb.Append("p[").Append(paramsExprs.Count - 1).Append("]=");
 9138            return pe.CreateExpressionString(sb, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType, i
 9139        }
 9140
 9141        internal static StringBuilder ToExpressionString(this LabelTarget lt, StringBuilder sb, List<LabelTarget> labelT
 9142            int lineIndent, bool stripNamespace, Func<Type, string, string> printType)
 9143        {
 9144            if (labelTargets.TryGetIndex(out var i, lt, labelTargets.Count, default(RefEq<LabelTarget>)))
 9145            {
 9146                SmallList<NamedWithIndex, Stack4<NamedWithIndex>> named = default;
 9147                return sb.Append("l[").Append(i)
 9148                    .Append(" // (").AppendName(lt, lt.Name, lt.Type.ToCode(stripNamespace, printType), ref named, lt.Ge
 9149                    .NewLineIndent(lineIndent).Append(']');
 9150            }
 9151            labelTargets.Add(lt);
 9152            sb.Append("l[").Append(labelTargets.Count - 1).Append("]=Label(");
 9153            sb.AppendTypeOf(lt.Type, stripNamespace, printType);
 9154
 9155            return (lt.Name != null ? sb.Append(", \"").Append(lt.Name).Append("\"") : sb).Append(")");
 9156        }
 9157
 9158        private static StringBuilder ToExpressionString(this IReadOnlyList<CatchBlock> bs, StringBuilder sb,
 9159            List<ParameterExpression> paramsExprs, List<Expression> uniqueExprs, List<LabelTarget> lts,
 9160            int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode no
 9161        {
 9162            if (bs.Count == 0)
 9163                return sb.Append("new CatchBlock[0]");
 9164            for (var i = 0; i < bs.Count; i++)
 9165                bs[i].ToExpressionString((i > 0 ? sb.Append(',') : sb).NewLineIndent(lineIndent),
 9166                    paramsExprs, uniqueExprs, lts, lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, n
 9167            return sb;
 9168        }
 9169
 9170        private static StringBuilder ToExpressionString(this CatchBlock b, StringBuilder sb,
 9171            List<ParameterExpression> paramsExprs, List<Expression> uniqueExprs, List<LabelTarget> lts,
 9172            int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode no
 9173        {
 9174            sb.Append("MakeCatchBlock(");
 9175            sb.NewLineIndent(lineIndent).AppendTypeOf(b.Test, stripNamespace, printType).Append(',');
 9176            sb.NewLineIndentExpr(b.Variable, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType, inden
 9177            sb.NewLineIndentExpr(b.Body, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType, indentSpa
 9178            sb.NewLineIndentExpr(b.Filter, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType, indentS
 9179            return sb.Append(')');
 9180        }
 9181
 9182        private static StringBuilder ToExpressionString(this IReadOnlyList<SwitchCase> items, StringBuilder sb,
 9183            List<ParameterExpression> paramsExprs, List<Expression> uniqueExprs, List<LabelTarget> lts,
 9184            int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode no
 9185        {
 9186            if (items.Count == 0)
 9187                return sb.Append("new SwitchCase[0]");
 9188            for (var i = 0; i < items.Count; i++)
 9189                items[i].ToExpressionString((i > 0 ? sb.Append(',') : sb).NewLineIndent(lineIndent),
 9190                    paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToC
 9191            return sb;
 9192        }
 9193
 9194        private static StringBuilder ToExpressionString(this SwitchCase s, StringBuilder sb,
 9195            List<ParameterExpression> paramsExprs, List<Expression> uniqueExprs, List<LabelTarget> lts,
 9196            int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode no
 9197        {
 9198            sb.Append("SwitchCase(");
 9199            sb.NewLineIndentExpr(s.Body, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType, indentSpa
 9200            sb.NewLineIndentArgumentExprs(s.TestValues, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, print
 9201            return sb.Append(')');
 9202        }
 9203
 9204        private static StringBuilder ToExpressionString(this MemberBinding mb, StringBuilder sb,
 9205            List<ParameterExpression> paramsExprs, List<Expression> uniqueExprs, List<LabelTarget> lts,
 9206            int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode no
 9207        {
 9208            if (mb is MemberAssignment ma)
 9209            {
 9210                sb.Append("Bind(");
 9211                sb.NewLineIndent(lineIndent).AppendMember(mb.Member, stripNamespace, printType).Append(", ");
 9212                sb.NewLineIndentExpr(ma.Expression, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType
 9213                return sb.Append(")");
 9214            }
 9215
 9216            if (mb is MemberMemberBinding mmb)
 9217            {
 9218                sb.NewLineIndent(lineIndent).Append(NotSupportedExpression).Append(nameof(MemberMemberBinding)).NewLineI
 9219                sb.Append("MemberBind(");
 9220                sb.NewLineIndent(lineIndent).AppendMember(mb.Member, stripNamespace, printType);
 9221
 9222                for (int i = 0; i < mmb.Bindings.Count; i++)
 9223                    mmb.Bindings[i].ToExpressionString(sb.Append(", ").NewLineIndent(lineIndent),
 9224                        paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType, indentSpaces, notRecognize
 9225                return sb.Append(")");
 9226            }
 9227
 9228            if (mb is MemberListBinding mlb)
 9229            {
 9230                sb.NewLineIndent(lineIndent).Append(NotSupportedExpression).Append(nameof(MemberListBinding)).NewLineInd
 9231                sb.Append("ListBind(");
 9232                sb.NewLineIndent(lineIndent).AppendMember(mb.Member, stripNamespace, printType);
 9233
 9234                for (int i = 0; i < mlb.Initializers.Count; i++)
 9235                    mlb.Initializers[i].ToExpressionString(sb.Append(", ").NewLineIndent(lineIndent),
 9236                        paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType, indentSpaces, notRecognize
 9237
 9238                return sb.Append(")");
 9239            }
 9240
 9241            return sb;
 9242        }
 9243
 9244        private static StringBuilder ToExpressionString(this ElementInit ei, StringBuilder sb,
 9245            List<ParameterExpression> paramsExprs, List<Expression> uniqueExprs, List<LabelTarget> lts,
 9246            int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode no
 9247        {
 9248            sb.Append("ElementInit(");
 9249            sb.NewLineIndent(lineIndent).AppendMethod(ei.AddMethod, stripNamespace, printType).Append(", ");
 9250            sb.NewLineIndentArgumentExprs(ei.Arguments, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, print
 9251            return sb.Append(")");
 9252        }
 9253
 9254        private const string NotSupportedExpression = "// NOT_SUPPORTED_EXPRESSION: ";
 9255
 9256        internal static StringBuilder CreateExpressionString(this Expression e, StringBuilder sb,
 9257            List<ParameterExpression> paramsExprs, List<Expression> uniqueExprs, List<LabelTarget> lts,
 9258            int lineIndent = 0, bool stripNamespace = false, Func<Type, string, string> printType = null, int indentSpac
 9259        {
 9260            switch (e.NodeType)
 9261            {
 9262                case ExpressionType.Constant:
 9263                    {
 9264                        var x = (ConstantExpression)e;
 9265                        sb.Append("Constant(");
 9266                        if (x.Value == null)
 9267                        {
 9268                            sb.Append("null");
 9269                            if (x.Type != typeof(object))
 9270                                sb.Append(", ").AppendTypeOf(x.Type, stripNamespace, printType);
 9271                        }
 9272                        else if (x.Value is Type t)
 9273                            sb.AppendTypeOf(t, stripNamespace, printType);
 9274                        else
 9275                        {
 9276                            sb.Append(x.Value.ToCode(notRecognizedToCode ?? CodePrinter.DefaultNotRecognizedToCode, stri
 9277                            if (x.Value.GetType() != x.Type)
 9278                                sb.Append(", ").AppendTypeOf(x.Type, stripNamespace, printType);
 9279                        }
 9280                        return sb.Append(')');
 9281                    }
 9282                case ExpressionType.Parameter:
 9283                    {
 9284                        var x = (ParameterExpression)e;
 9285                        sb.Append("Parameter(").AppendTypeOf(x.Type, stripNamespace, printType);
 9286                        if (x.IsByRef)
 9287                            sb.Append(".MakeByRefType()");
 9288                        if (x.Name != null)
 9289                            sb.Append(", \"").Append(x.Name).Append('"');
 9290                        return sb.Append(')');
 9291                    }
 9292                case ExpressionType.New:
 9293                    {
 9294                        var x = (NewExpression)e;
 9295                        var args = x.Arguments;
 9296
 9297                        if (args.Count == 0 && e.Type.IsValueType)
 9298                            return sb.Append("New(").AppendTypeOf(e.Type, stripNamespace, printType).Append(')');
 9299
 9300                        sb.Append("New( // ").Append(args.Count).Append(" args");
 9301                        var ctorIndex = x.Constructor.DeclaringType.GetTypeInfo().DeclaredConstructors.AsArray().GetFirs
 9302                        sb.NewLineIndent(lineIndent).AppendTypeOf(x.Type, stripNamespace, printType)
 9303                            .Append(".GetTypeInfo().DeclaredConstructors.AsArray()[").Append(ctorIndex).Append("],");
 9304                        sb.NewLineIndentArgumentExprs(args, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, p
 9305                        return sb.Append(')');
 9306                    }
 9307                case ExpressionType.Call:
 9308                    {
 9309                        var mc = (MethodCallExpression)e;
 9310                        var diffTypes = mc.Type != mc.Method.ReturnType;
 9311                        sb.Append(diffTypes ? "Convert(Call(" : "Call(");
 9312                        sb.NewLineIndentExpr(mc.Object, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, print
 9313                        sb.NewLineIndent(lineIndent).AppendMethod(mc.Method, stripNamespace, printType);
 9314                        if (mc.Arguments.Count > 0)
 9315                            sb.Append(',').NewLineIndentArgumentExprs(mc.Arguments, paramsExprs, uniqueExprs, lts, lineI
 9316                        return diffTypes ? sb.Append("), ").AppendTypeOf(e.Type, stripNamespace, printType).Append(')') 
 9317                    }
 9318                case ExpressionType.MemberAccess:
 9319                    {
 9320                        var x = (MemberExpression)e;
 9321                        if (x.Member is PropertyInfo p)
 9322                        {
 9323                            sb.Append("Property(");
 9324                            sb.NewLineIndentExpr(x.Expression, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace
 9325                            sb.NewLineIndent(lineIndent).AppendProperty(p, stripNamespace, printType);
 9326                        }
 9327                        else
 9328                        {
 9329                            sb.Append("Field(");
 9330                            sb.NewLineIndentExpr(x.Expression, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace
 9331                            sb.NewLineIndent(lineIndent).AppendField((FieldInfo)x.Member, stripNamespace, printType);
 9332                        }
 9333                        return sb.Append(')');
 9334                    }
 9335
 9336                case ExpressionType.NewArrayBounds:
 9337                case ExpressionType.NewArrayInit:
 9338                    {
 9339                        var x = (NewArrayExpression)e;
 9340                        if (e.NodeType == ExpressionType.NewArrayInit)
 9341                        {
 9342                            // todo: @feature multi-dimensional array initializers are not supported yet, they also are 
 9343                            if (e.Type.GetArrayRank() > 1)
 9344                                sb.NewLineIndent(lineIndent).Append(NotSupportedExpression).Append(e.NodeType).NewLineIn
 9345                            sb.Append("NewArrayInit(");
 9346                        }
 9347                        else
 9348                        {
 9349                            sb.Append("NewArrayBounds(");
 9350                        }
 9351                        sb.NewLineIndent(lineIndent).AppendTypeOf(x.Type.GetElementType(), stripNamespace, printType).Ap
 9352                        sb.NewLineIndentArgumentExprs(x.Expressions, paramsExprs, uniqueExprs, lts, lineIndent, stripNam
 9353                        return sb.Append(')');
 9354                    }
 9355                case ExpressionType.MemberInit:
 9356                    {
 9357                        var x = (MemberInitExpression)e;
 9358                        sb.Append("MemberInit((NewExpression)(");
 9359                        sb.NewLineIndentExpr(x.NewExpression, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace,
 9360                          .Append(')');
 9361                        for (var i = 0; i < x.Bindings.Count; i++)
 9362                            x.Bindings[i].ToExpressionString(sb.Append(", ").NewLineIndent(lineIndent),
 9363                                paramsExprs, uniqueExprs, lts, lineIndent + indentSpaces, stripNamespace, printType, ind
 9364                        return sb.Append(')');
 9365                    }
 9366                case ExpressionType.Lambda:
 9367                    {
 9368                        var x = (LambdaExpression)e;
 9369                        sb.Append("Lambda<").Append(x.Type.ToCode(stripNamespace, printType)).Append(">(");
 9370                        sb.NewLineIndentExpr(x.Body, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printTyp
 9371                        sb.NewLineIndentArgumentExprs(x.Parameters, paramsExprs, uniqueExprs, lts, lineIndent, stripName
 9372                        return sb.Append(')');
 9373                    }
 9374                case ExpressionType.Invoke:
 9375                    {
 9376                        var x = (InvocationExpression)e;
 9377                        sb.Append("Invoke(");
 9378                        sb.NewLineIndentExpr(x.Expression, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, pr
 9379                        sb.NewLineIndentArgumentExprs(x.Arguments, paramsExprs, uniqueExprs, lts, lineIndent, stripNames
 9380                        return sb.Append(")");
 9381                    }
 9382                case ExpressionType.Conditional:
 9383                    {
 9384                        var x = (ConditionalExpression)e;
 9385                        sb.Append("Condition(");
 9386                        sb.NewLineIndentExpr(x.Test, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printTyp
 9387                        sb.NewLineIndentExpr(x.IfTrue, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printT
 9388                        sb.NewLineIndentExpr(x.IfFalse, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, print
 9389                        sb.NewLineIndent(lineIndent).AppendTypeOf(x.Type, stripNamespace, printType);
 9390                        return sb.Append(')');
 9391                    }
 9392                case ExpressionType.Block:
 9393                    {
 9394                        var x = (BlockExpression)e;
 9395                        sb.Append("Block(");
 9396                        sb.NewLineIndent(lineIndent).AppendTypeOf(x.Type, stripNamespace, printType).Append(',');
 9397
 9398                        if (x.Variables.Count == 0)
 9399                            sb.NewLineIndent(lineIndent).Append("new ParameterExpression[0], ");
 9400                        else
 9401                        {
 9402                            sb.NewLineIndent(lineIndent).Append("new[] {");
 9403                            for (var i = 0; i < x.Variables.Count; i++)
 9404                                x.Variables[i].ToExpressionString(
 9405                                    (i > 0 ? sb.Append(',') : sb).NewLineIndent(lineIndent + indentSpaces),
 9406                                    paramsExprs, uniqueExprs, lts, lineIndent + indentSpaces, stripNamespace, printType,
 9407                            sb.NewLineIndent(lineIndent).Append("},");
 9408                        }
 9409
 9410                        sb.NewLineIndentArgumentExprs(x.Expressions, paramsExprs, uniqueExprs, lts, lineIndent, stripNam
 9411                        return sb.Append(')');
 9412                    }
 9413                case ExpressionType.Loop:
 9414                    {
 9415                        var x = (LoopExpression)e;
 9416                        sb.Append("Loop(");
 9417                        sb.NewLineIndentExpr(x.Body, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printTyp
 9418
 9419                        if (x.BreakLabel != null)
 9420                            x.BreakLabel.ToExpressionString(sb.Append(',').NewLineIndent(lineIndent), lts, lineIndent, s
 9421
 9422                        if (x.ContinueLabel != null)
 9423                            x.ContinueLabel.ToExpressionString(sb.Append(',').NewLineIndent(lineIndent), lts, lineIndent
 9424
 9425                        return sb.Append(')');
 9426                    }
 9427                case ExpressionType.Index:
 9428                    {
 9429                        var x = (IndexExpression)e;
 9430                        sb.Append(x.Indexer != null ? "MakeIndex(" : "ArrayAccess(");
 9431                        sb.NewLineIndentExpr(x.Object, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printT
 9432
 9433                        if (x.Indexer != null)
 9434                            sb.NewLineIndent(lineIndent).AppendProperty(x.Indexer, stripNamespace, printType).Append(", 
 9435
 9436                        sb.Append("new Expression[] {");
 9437                        for (var i = 0; i < x.Arguments.Count; i++)
 9438                            (i > 0 ? sb.Append(',') : sb)
 9439                            .NewLineIndentExpr(x.Arguments[i], paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace
 9440                        return sb.Append("})");
 9441                    }
 9442                case ExpressionType.Try:
 9443                    {
 9444                        var x = (TryExpression)e;
 9445                        if (x.Fault != null)
 9446                        {
 9447                            sb.Append("TryFault(");
 9448                            sb.NewLineIndentExpr(x.Body, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, prin
 9449                            sb.NewLineIndentExpr(x.Fault, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, pri
 9450                        }
 9451                        else if (x.Finally == null)
 9452                        {
 9453                            sb.Append("TryCatch(");
 9454                            sb.NewLineIndentExpr(x.Body, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, prin
 9455                            x.Handlers.ToExpressionString(sb, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace,
 9456                        }
 9457                        else if (x.Handlers == null)
 9458                        {
 9459                            sb.Append("TryFinally(");
 9460                            sb.NewLineIndentExpr(x.Body, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, prin
 9461                            sb.NewLineIndentExpr(x.Finally, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, p
 9462                        }
 9463                        else
 9464                        {
 9465                            sb.Append("TryCatchFinally(");
 9466                            sb.NewLineIndentExpr(x.Body, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, prin
 9467                            sb.NewLineIndentExpr(x.Finally, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, p
 9468                            x.Handlers.ToExpressionString(sb, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace,
 9469                        }
 9470
 9471                        return sb.Append(')');
 9472                    }
 9473                case ExpressionType.Label:
 9474                    {
 9475                        var x = (LabelExpression)e;
 9476                        sb.Append("Label(");
 9477                        x.Target.ToExpressionString(sb, lts, lineIndent, stripNamespace, printType);
 9478                        if (x.DefaultValue != null)
 9479                            sb.Append(',').NewLineIndentExpr(x.DefaultValue, paramsExprs, uniqueExprs, lts, lineIndent, 
 9480                        return sb.Append(')');
 9481                    }
 9482                case ExpressionType.Goto:
 9483                    {
 9484                        var x = (GotoExpression)e;
 9485                        sb.Append("MakeGoto(").AppendEnum(x.Kind, stripNamespace, printType).Append(',');
 9486
 9487                        sb.NewLineIndent(lineIndent);
 9488                        x.Target.ToExpressionString(sb, lts, lineIndent, stripNamespace, printType).Append(',');
 9489
 9490                        sb.NewLineIndentExpr(x.Value, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printTy
 9491                        sb.NewLineIndent(lineIndent).AppendTypeOf(x.Type, stripNamespace, printType);
 9492                        return sb.Append(')');
 9493                    }
 9494                case ExpressionType.Switch:
 9495                    {
 9496                        var x = (SwitchExpression)e;
 9497                        sb.Append("Switch(");
 9498                        sb.NewLineIndentExpr(x.SwitchValue, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, p
 9499                        sb.NewLineIndentExpr(x.DefaultBody, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, p
 9500                        sb.NewLineIndent(lineIndent).AppendMethod(x.Comparison, stripNamespace, printType);
 9501                        ToExpressionString(x.Cases, sb, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, print
 9502                        return sb.Append(')');
 9503                    }
 9504                case ExpressionType.Default:
 9505                    {
 9506                        return e.Type == typeof(void) ? sb.Append("Empty()")
 9507                            : sb.Append("Default(").AppendTypeOf(e.Type, stripNamespace, printType).Append(')');
 9508                    }
 9509                case ExpressionType.TypeIs:
 9510                case ExpressionType.TypeEqual:
 9511                    {
 9512                        var x = (TypeBinaryExpression)e;
 9513                        sb.Append(e.NodeType == ExpressionType.TypeIs ? "TypeIs(" : "TypeEqual(");
 9514                        sb.NewLineIndentExpr(x.Expression, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, pr
 9515                        sb.NewLineIndent(lineIndent).AppendTypeOf(x.TypeOperand, stripNamespace, printType);
 9516                        return sb.Append(')');
 9517                    }
 9518                case ExpressionType.Coalesce:
 9519                    {
 9520                        var x = (BinaryExpression)e;
 9521                        sb.Append("Coalesce(");
 9522                        sb.NewLineIndentExpr(x.Left, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printTyp
 9523                        sb.NewLineIndentExpr(x.Right, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printTy
 9524                        if (x.Conversion != null)
 9525                            sb.Append(',').NewLineIndentExpr(x.Conversion, paramsExprs, uniqueExprs, lts, lineIndent, st
 9526                        return sb.Append(')');
 9527                    }
 9528                case ExpressionType.ListInit:
 9529                    {
 9530                        var x = (ListInitExpression)e;
 9531                        sb.Append("ListInit((NewExpression)(");
 9532                        sb.NewLineIndentExpr(x.NewExpression, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace,
 9533                        for (var i = 0; i < x.Initializers.Count; i++)
 9534                            x.Initializers[i].ToExpressionString(sb.Append(", ").NewLineIndent(lineIndent),
 9535                                paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType, indentSpaces, notR
 9536                        return sb.Append(")");
 9537                    }
 9538                case ExpressionType.Extension:
 9539                    {
 9540                        var reduced = e.Reduce(); // proceed with the reduced expression
 9541                        return reduced.CreateExpressionString(sb, paramsExprs, uniqueExprs, lts, lineIndent, stripNamesp
 9542                    }
 9543                case ExpressionType.Dynamic:
 9544                case ExpressionType.RuntimeVariables:
 9545                case ExpressionType.DebugInfo:
 9546                case ExpressionType.Quote:
 9547                    {
 9548                        return sb.NewLineIndent(lineIndent).Append(NotSupportedExpression).Append(e.NodeType).NewLineInd
 9549                    }
 9550                default:
 9551                    {
 9552                        var name = Enum.GetName(typeof(ExpressionType), e.NodeType);
 9553                        if (e is UnaryExpression u)
 9554                        {
 9555                            sb.Append(name).Append('(');
 9556                            // todo: @feature maybe for big expression it makes sense to print the Type in comment here 
 9557                            sb.NewLineIndentExpr(u.Operand, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, p
 9558
 9559                            if (e.NodeType == ExpressionType.Convert ||
 9560                                e.NodeType == ExpressionType.ConvertChecked ||
 9561                                e.NodeType == ExpressionType.Unbox ||
 9562                                e.NodeType == ExpressionType.Throw ||
 9563                                e.NodeType == ExpressionType.TypeAs)
 9564                                sb.Append(',').NewLineIndent(lineIndent).AppendTypeOf(e.Type, stripNamespace, printType)
 9565
 9566                            if ((e.NodeType == ExpressionType.Convert || e.NodeType == ExpressionType.ConvertChecked)
 9567                                && u.Method != null)
 9568                                sb.Append(',').NewLineIndent(lineIndent).AppendMethod(u.Method, stripNamespace, printTyp
 9569                        }
 9570
 9571                        if (e is BinaryExpression b)
 9572                        {
 9573                            sb.Append("MakeBinary(").Append(typeof(ExpressionType).Name).Append('.').Append(name).Append
 9574                            sb.NewLineIndentExpr(b.Left, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, prin
 9575                            sb.NewLineIndentExpr(b.Right, paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, pri
 9576                            if (b.IsLiftedToNull || b.Method != null)
 9577                            {
 9578                                sb.Append(',').NewLineIndent(lineIndent).Append("liftToNull: ").Append(b.IsLiftedToNull.
 9579                                sb.Append(',').NewLineIndent(lineIndent).AppendMethod(b.Method, stripNamespace, printTyp
 9580                                if (b.Conversion != null)
 9581                                    sb.Append(',').NewLineIndentExpr(b.Conversion, paramsExprs, uniqueExprs, lts, lineIn
 9582                            }
 9583
 9584                            if (b.Conversion != null)
 9585                                sb.Append(',').NewLineIndentExpr(b.Conversion, paramsExprs, uniqueExprs, lts, lineIndent
 9586                        }
 9587
 9588                        return sb.Append(')');
 9589                    }
 9590            }
 9591        }
 9592    }
 9593
 9594    /// <summary>Converts the expression into the valid C# code representation</summary>
 9595    [RequiresUnreferencedCode(Trimming.Message)]
 9596    internal static class ToCSharpPrinter
 9597    {
 9598        /// <summary>Tries hard to convert the expression into the valid C# code</summary>
 9599        public static string ToCSharpString(this Expression expr) =>
 9600            expr.ToCSharpString(new StringBuilder(1024), stripNamespace: true).Append(';').ToString();
 9601
 9602        /// <summary>Tries hard to convert the expression into the valid C# code</summary>
 9603        public static string ToCSharpString(this Expression expr, ObjectToCode notRecognizedToCode) =>
 9604            expr.ToCSharpString(new StringBuilder(1024), stripNamespace: true, notRecognizedToCode: notRecognizedToCode)
 9605
 9606        /// <summary>Tries hard to convert the expression into the valid C# code</summary>
 9607        public static StringBuilder ToCSharpString(this Expression e, StringBuilder sb,
 9608            int lineIndent = 0, bool stripNamespace = false, Func<Type, string, string> printType = null, int indentSpac
 9609        {
 9610            SmallList<NamedWithIndex, Stack4<NamedWithIndex>> named = default;
 9611            return e.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 9612                lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9613        }
 9614
 9615        /// <summary>Indicates the expression container</summary>
 9616        internal enum EnclosedIn
 9617        {
 9618            /// <summary>Prefers the parens by default</summary>
 9619            ParensByDefault = 0,
 9620            /// <summary>The test part of the If expression</summary>
 9621            IfTest,
 9622            /// <summary>The `if (test)` part</summary>
 9623            Block,
 9624            /// <summary>The lambda</summary>
 9625            LambdaBody,
 9626            /// <summary>Return expression</summary>
 9627            Return,
 9628            /// <summary>Instructs the client code to avoid parenthesis for the generated C# code, e.g. if we have as si
 9629            AvoidParens,
 9630            /// <summary>The instance when calling the instance method or accessing the instance member</summary>
 9631            Instance,
 9632        }
 9633
 9634        private static StringBuilder NullConstantOrDefaultToCSharpString(Type exprType, StringBuilder sb, EnclosedIn enc
 9635            bool stripNamespace, Func<Type, string, string> printType) =>
 9636            exprType == typeof(object)
 9637                ? sb.Append("null")
 9638            : exprType.IsValueType && !exprType.IsNullable()
 9639                ? sb.Append("default(").Append(exprType.ToCode(stripNamespace, printType)).Append(')')
 9640                : sb.Append(encloseIn == EnclosedIn.Instance ? "((" : "(")
 9641                    .Append(exprType.ToCode(stripNamespace, printType)).Append(")null")
 9642                    .Append(encloseIn == EnclosedIn.Instance ? ")" : "");
 9643
 9644        private static StringBuilder InsertTopFFuncDefinitionOnce(StringBuilder sb) =>
 9645            sb[0] != 'T' || sb[2] != '_' || sb[3] != '_' || sb[4] != 'f' || sb[5] != '<'
 9646                ? sb.Insert(0, "T __f<T>(System.Func<T> f) => f();\n")
 9647                : sb;
 9648
 9649        internal static StringBuilder ToCSharpString(this Expression e,
 9650            StringBuilder sb, EnclosedIn enclosedIn, ref SmallList<NamedWithIndex, Stack4<NamedWithIndex>> named,
 9651            int lineIndent = 0, bool stripNamespace = false, Func<Type, string, string> printType = null, int indentSpac
 9652            ObjectToCode notRecognizedToCode = null, bool isReturnByRef = false)
 9653        {
 9654#if LIGHT_EXPRESSION
 9655            if (e.IsCustomToCSharpString)
 9656                return e.CustomToCSharpString(sb, enclosedIn, ref named,
 9657                    lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9658#endif
 9659            switch (e.NodeType)
 9660            {
 9661                case ExpressionType.Constant:
 9662                    {
 9663                        var x = (ConstantExpression)e;
 9664                        if (x.Value == null)
 9665                            return x.Type == null ? sb.Append("null") : NullConstantOrDefaultToCSharpString(x.Type, sb, 
 9666
 9667                        if (x.Value is Type t)
 9668                            return sb.AppendTypeOf(t, stripNamespace, printType);
 9669
 9670                        if (x.Value.GetType() != x.Type) // add the Type cast
 9671                            sb.Append('(').Append(x.Type.ToCode(stripNamespace, printType)).Append(')');
 9672
 9673                        // value output may also add the cast for the primitive values
 9674                        return sb.Append(x.Value.ToCode(notRecognizedToCode ?? CodePrinter.DefaultNotRecognizedToCode, s
 9675                    }
 9676                case ExpressionType.Parameter:
 9677                    {
 9678                        if (isReturnByRef)
 9679                            sb.Append("ref ");
 9680                        return sb.AppendName(e, ((ParameterExpression)e).Name, e.Type.ToCode(stripNamespace, printType),
 9681                    }
 9682                case ExpressionType.New:
 9683                    {
 9684                        var x = (NewExpression)e;
 9685                        lineIndent = sb.GetRealLineIndent(lineIndent);
 9686                        var argIndent = lineIndent + indentSpaces;
 9687
 9688                        sb.Append("new ").Append(e.Type.ToCode(stripNamespace, printType)).Append('(');
 9689
 9690                        var args = x.Arguments;
 9691                        if (args.Count == 1)
 9692                            args[0].ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 9693                                lineIndent, // don't increase indent the chain of single arguments inline, e.g. for `new
 9694                                stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9695                        else if (args.Count > 1)
 9696                            for (var i = 0; i < args.Count; i++)
 9697                            {
 9698                                (i > 0 ? sb.Append(',') : sb).NewLineIndent(argIndent);
 9699                                args[i].ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 9700                                    argIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9701                            }
 9702                        return sb.Append(')');
 9703                    }
 9704                case ExpressionType.Call:
 9705                    {
 9706                        var mc = (MethodCallExpression)e;
 9707
 9708                        // before adding anything about method call to the builder,
 9709                        // let's measure the current indent to avoid the double indenting the arguments below in some ca
 9710                        lineIndent = sb.GetRealLineIndent(lineIndent);
 9711                        var argIndent = lineIndent + indentSpaces;
 9712
 9713                        var method = mc.Method;
 9714                        var methodReturnType = method.ReturnType;
 9715                        if (methodReturnType.IsByRef)
 9716                            sb.Append("ref ");
 9717
 9718                        // output convert only if it is required, e.g. it may happen for custom expressions designed by 
 9719                        var diffTypes = mc.Type != methodReturnType;
 9720                        if (diffTypes) sb.Append("((").Append(mc.Type.ToCode(stripNamespace, printType)).Append(')');
 9721
 9722                        if (mc.Object != null)
 9723                            mc.Object.ToCSharpString(sb, EnclosedIn.Instance, ref named,
 9724                                lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9725                        else // for the static method or the static extension method we need to qualify with the class
 9726                            sb.Append(method.DeclaringType.ToCode(stripNamespace, printType));
 9727
 9728                        var name = method.Name;
 9729                        // check for the special methods, e.g. property access `get_` or `set_` and output them as prope
 9730                        if (method.IsSpecialName)
 9731                        {
 9732                            if (name.StartsWith("get_"))
 9733                                return sb.Append('.').Append(name.Substring(4));
 9734                            if (name.StartsWith("set_"))
 9735                            {
 9736                                sb.Append('.').Append(name.Substring(4)).Append(" = ");
 9737                                mc.Arguments[0].ToCSharpExpression(sb, EnclosedIn.AvoidParens, ref named,
 9738                                    false, lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9739                                return sb.AppendSemicolonOnce();
 9740                            }
 9741                        }
 9742
 9743                        sb.Append('.').Append(name);
 9744                        if (method.IsGenericMethod)
 9745                        {
 9746                            sb.Append('<');
 9747                            var typeArgs = method.GetGenericArguments();
 9748                            for (var i = 0; i < typeArgs.Length; i++)
 9749                                (i == 0 ? sb : sb.Append(", ")).Append(typeArgs[i].ToCode(stripNamespace, printType));
 9750                            sb.Append('>');
 9751                        }
 9752
 9753                        sb.Append('(');
 9754                        var pars = method.GetParameters();
 9755                        var args = mc.Arguments;
 9756                        if (args.Count == 1)
 9757                        {
 9758                            var p = pars[0];
 9759                            var a = args[0];
 9760                            if (p.ParameterType.IsByRef && !a.IsConstantOrDefault())
 9761                                sb.Append(p.IsOut ? "out " : p.IsIn ? "in" : "ref ");
 9762                            a.ToCSharpExpression(sb, EnclosedIn.AvoidParens, ref named,
 9763                                false, lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9764                        }
 9765                        else if (args.Count > 1)
 9766                        {
 9767                            for (var i = 0; i < args.Count; i++)
 9768                            {
 9769                                // arguments will start at that minimal indent
 9770                                (i == 0 ? sb : sb.Append(',')).NewLineIndent(argIndent);
 9771                                var p = pars[i];
 9772                                var a = args[i];
 9773                                if (p.ParameterType.IsByRef && !a.IsConstantOrDefault())
 9774                                    sb.Append(p.IsOut ? "out " : p.IsIn ? "in " : "ref ");
 9775                                a.ToCSharpExpression(sb, EnclosedIn.AvoidParens, ref named,
 9776                                    false, argIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9777                            }
 9778                        }
 9779                        // for the different return and expression types wrapping the whole expression including the cas
 9780                        return diffTypes ? sb.Append("))") : sb.Append(')');
 9781                    }
 9782                case ExpressionType.MemberAccess:
 9783                    {
 9784                        var x = (MemberExpression)e;
 9785                        var inst = x.Expression;
 9786                        if (inst != null)
 9787                        {
 9788                            // wrap the `new X().Y` into parens as `(new X()).Y` as it is may be a part of the bigger ex
 9789                            if (inst.NodeType == ExpressionType.New)
 9790                                sb.Append('(');
 9791                            inst.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 9792                                lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9793                            if (inst.NodeType == ExpressionType.New)
 9794                                sb.Append(')');
 9795                        }
 9796                        else
 9797                            sb.Append(x.Member.DeclaringType.ToCode(stripNamespace, printType));
 9798                        return sb.Append('.').Append(x.Member.GetCSharpName());
 9799                    }
 9800                case ExpressionType.NewArrayBounds:
 9801                case ExpressionType.NewArrayInit:
 9802                    {
 9803                        var x = (NewArrayExpression)e;
 9804                        lineIndent = sb.GetRealLineIndent(lineIndent);
 9805                        var nextIndent = lineIndent + indentSpaces;
 9806
 9807                        sb.Append("new ").Append(e.Type.GetElementType().ToCode(stripNamespace, printType));
 9808                        sb.Append(e.NodeType == ExpressionType.NewArrayInit ? "[]{" : "[");
 9809
 9810                        var exprs = x.Expressions;
 9811                        if (exprs.Count == 1)
 9812                            exprs[0].ToCSharpString(sb, EnclosedIn.AvoidParens, ref named,
 9813                                lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9814                        else if (exprs.Count > 1)
 9815                            for (var i = 0; i < exprs.Count; i++)
 9816                            {
 9817                                sb = (i > 0 ? sb.Append(',') : sb).NewLineIndent(nextIndent);
 9818                                exprs[i].ToCSharpString(sb, EnclosedIn.AvoidParens, ref named,
 9819                                    nextIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9820                            }
 9821
 9822                        return sb.Append(e.NodeType == ExpressionType.NewArrayInit ? "}" : "]");
 9823                    }
 9824                case ExpressionType.MemberInit:
 9825                    {
 9826                        var x = (MemberInitExpression)e;
 9827                        lineIndent = sb.GetRealLineIndent(lineIndent);
 9828
 9829                        x.NewExpression.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 9830                            lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9831                        sb.NewLineIndent(lineIndent).Append('{');
 9832                        x.Bindings.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named, lineIndent + indentSpaces, 
 9833                        return sb.NewLineIndent(lineIndent).Append('}');
 9834                    }
 9835                case ExpressionType.ListInit:
 9836                    {
 9837                        var x = (ListInitExpression)e;
 9838                        lineIndent = sb.GetRealLineIndent(lineIndent);
 9839                        var elemIndent = lineIndent + indentSpaces;
 9840
 9841                        x.NewExpression.ToCSharpString(sb, EnclosedIn.AvoidParens, ref named,
 9842                            lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9843
 9844                        sb.NewLineIndent(lineIndent).Append('{');
 9845
 9846                        var inits = x.Initializers;
 9847                        for (var i = 0; i < inits.Count; ++i)
 9848                        {
 9849                            (i == 0 ? sb : sb.Append(", ")).NewLineIndent(elemIndent);
 9850                            var elemInit = inits[i];
 9851                            var args = elemInit.Arguments;
 9852                            if (args.Count == 1)
 9853                            {
 9854                                args.GetArgument(0).ToCSharpString(sb, EnclosedIn.AvoidParens, ref named,
 9855                                    elemIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9856                            }
 9857                            else
 9858                            {
 9859                                sb.Append('{');
 9860                                for (var j = 0; j < args.Count; ++j)
 9861                                {
 9862                                    sb = j == 0 ? sb : sb.Append(", ");
 9863                                    args.GetArgument(j).ToCSharpString(sb, EnclosedIn.AvoidParens, ref named,
 9864                                        elemIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9865                                }
 9866                                sb.Append('}');
 9867                            }
 9868                        }
 9869                        return sb.NewLineIndent(lineIndent).Append("}");
 9870                    }
 9871                case ExpressionType.Lambda:
 9872                    {
 9873                        var x = (LambdaExpression)e;
 9874                        lineIndent = sb.GetRealLineIndent(lineIndent);
 9875                        // The result should be something like this (taken from the #237)
 9876                        //
 9877                        // `(DeserializerDlg<Word>)((ref ReadOnlySequence<Byte> input, Word value, out Int64 bytesRead) 
 9878                        //
 9879                        sb.Append('(').Append(e.Type.ToCode(stripNamespace, printType)).Append(")((");
 9880                        var lambdaMethod = x.Type.FindDelegateInvokeMethod();
 9881                        var count = x.Parameters.Count;
 9882                        if (count > 0)
 9883                        {
 9884                            var pars = lambdaMethod.GetParameters();
 9885                            for (var i = 0; i < count; i++)
 9886                            {
 9887                                if (i > 0)
 9888                                    sb.Append(", ");
 9889                                if (count > 1)
 9890                                    sb.NewLineIndent(lineIndent + indentSpaces);
 9891
 9892                                var pe = x.Parameters[i];
 9893                                var p = pars[i];
 9894                                if (pe.IsByRef)
 9895                                    sb.Append(p.IsOut ? "out " : p.IsIn ? "in " : "ref ");
 9896                                var typeCode = pe.Type.ToCode(stripNamespace, printType);
 9897                                sb.Append(typeCode).Append(' ');
 9898                                sb.AppendName(pe, pe.Name, typeCode, ref named);
 9899                            }
 9900                        }
 9901
 9902                        sb.Append(") => //").Append(lambdaMethod.ReturnType.ToCode(stripNamespace, printType));
 9903                        var body = x.Body;
 9904                        var bNodeType = body.NodeType;
 9905                        var isReturnable = bNodeType.IsReturnable();
 9906                        var ignoresResult = x.ReturnType == typeof(void);
 9907                        if (isReturnable & !ignoresResult)
 9908                        {
 9909                            var newLineIndent = lineIndent + indentSpaces;
 9910                            sb.NewLineIndent(newLineIndent);
 9911                            body.ToCSharpString(sb, EnclosedIn.LambdaBody, ref named,
 9912                                newLineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode, lambdaMetho
 9913                        }
 9914                        else
 9915                        {
 9916                            sb.NewLineIndent(lineIndent).Append('{');
 9917                            // Body handles `;` itself
 9918                            if (body is BlockExpression bb)
 9919                                bb.BlockToCSharpString(sb, ref named,
 9920                                    lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToC
 9921                                    inTheLastBlock: true, containerIgnoresResult: ignoresResult);
 9922                            else
 9923                            {
 9924                                sb.NewLineIndent(lineIndent + indentSpaces);
 9925                                body.ToCSharpString(sb, EnclosedIn.LambdaBody, ref named,
 9926                                    lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToC
 9927                                if (isReturnable)
 9928                                    sb.AppendSemicolonOnce();
 9929                            }
 9930                            sb.NewLineIndent(lineIndent).Append('}');
 9931                        }
 9932                        return sb.Append(')');
 9933                    }
 9934                case ExpressionType.Invoke:
 9935                    {
 9936                        var x = (InvocationExpression)e;
 9937
 9938                        lineIndent = sb.GetRealLineIndent(lineIndent);
 9939                        var argIndent = lineIndent + indentSpaces;
 9940
 9941                        // wrap the expression in the possibly excessive parentheses, because usually the expression is 
 9942                        // which should be cast to the proper delegate type, e.g. `(Func<int>)(() => 1)`, so we need an 
 9943                        var encloseInParens = x.Expression.NodeType != ExpressionType.Parameter;
 9944                        if (encloseInParens)
 9945                            sb.Append('(');
 9946                        x.Expression.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 9947                            lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9948                        if (encloseInParens)
 9949                            sb.Append(')');
 9950
 9951                        // Indicates the lambda invocation more explicitly with the new line,
 9952                        // Keep Invoke indentation the same as the lambda closing brace indicating their bond
 9953                        if (x.Expression.NodeType == ExpressionType.Lambda)
 9954                            sb.NewLineIndent(lineIndent);
 9955                        sb.Append(".Invoke(");
 9956
 9957                        for (var i = 0; i < x.Arguments.Count; i++)
 9958                        {
 9959                            sb = i > 0 ? sb.Append(',') : sb;
 9960                            sb.NewLineIndent(argIndent);
 9961                            x.Arguments[i].ToCSharpString(sb, EnclosedIn.AvoidParens, ref named,
 9962                                argIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9963                        }
 9964                        return sb.Append(")");
 9965                    }
 9966                case ExpressionType.Conditional:
 9967                    {
 9968                        var x = (ConditionalExpression)e;
 9969                        lineIndent = sb.GetRealLineIndent(lineIndent);
 9970
 9971                        if (e.Type == typeof(void)) // otherwise output as ternary expression
 9972                        {
 9973                            sb.Append("if (");
 9974                            x.Test.ToCSharpString(sb, EnclosedIn.IfTest, ref named,
 9975                                lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9976                            sb.Append(')');
 9977
 9978                            x.IfTrue.ToCSharpBlock(sb, ref named,
 9979                                lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9980
 9981                            if (x.IfFalse.NodeType != ExpressionType.Default || x.IfFalse.Type != typeof(void))
 9982                            {
 9983                                sb.NewLineIndent(lineIndent).Append("else");
 9984                                x.IfFalse.ToCSharpBlock(sb, ref named,
 9985                                    lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9986                            }
 9987                        }
 9988                        else
 9989                        {
 9990                            var avoidParens = AvoidParens(enclosedIn);
 9991                            sb = avoidParens ? sb : sb.Append('(');
 9992
 9993                            x.Test.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 9994                                lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 9995
 9996                            sb.Append(" ? ");
 9997                            var doNewLine = !x.IfTrue.IsParamOrConstantOrDefault();
 9998                            x.IfTrue.ToCSharpExpression(sb, EnclosedIn.AvoidParens, ref named,
 9999                                doNewLine, lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecogn
 10000
 10001                            sb.Append(" : ");
 10002                            doNewLine = !x.IfFalse.IsParamOrConstantOrDefault();
 10003                            x.IfFalse.ToCSharpExpression(sb, EnclosedIn.AvoidParens, ref named,
 10004                                doNewLine, lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecogn
 10005
 10006                            sb = avoidParens ? sb : sb.Append(')');
 10007                        }
 10008                        return sb;
 10009                    }
 10010                case ExpressionType.Block:
 10011                    {
 10012                        return ((BlockExpression)e).BlockToCSharpString(sb, ref named,
 10013                            lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10014                    }
 10015                case ExpressionType.Loop:
 10016                    {
 10017                        var x = (LoopExpression)e;
 10018                        lineIndent = sb.GetRealLineIndent(lineIndent);
 10019
 10020                        sb.NewLineIndent(lineIndent).Append("while (true)");
 10021                        sb.NewLineIndent(lineIndent).Append("{");
 10022
 10023                        if (x.ContinueLabel != null)
 10024                        {
 10025                            sb.NewLineIndent(lineIndent);
 10026                            sb.AppendLabelName(x.ContinueLabel, ref named)
 10027                                .Append(":;"); // the label is with the semicolon, because it will invalid code at the e
 10028                        }
 10029
 10030                        sb.NewLineIndent(lineIndent + indentSpaces);
 10031                        x.Body.ToCSharpString(sb, EnclosedIn.AvoidParens, ref named,
 10032                            lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10033
 10034                        sb.NewLineIndent(lineIndent).Append("}");
 10035
 10036                        // the label is with the semicolon, because it will invalid code at the end of lambda without it
 10037                        if (x.BreakLabel != null)
 10038                            sb.NewLineIndent(lineIndent).AppendLabelName(x.BreakLabel, ref named).Append(":;");
 10039
 10040                        return sb;
 10041                    }
 10042                case ExpressionType.Index:
 10043                    {
 10044                        var x = (IndexExpression)e;
 10045                        x.Object.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10046                            lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10047
 10048                        var isStandardIndexer = x.Indexer == null || x.Indexer.Name == "Item";
 10049                        if (isStandardIndexer)
 10050                            sb.Append('[');
 10051                        else
 10052                            sb.Append('.').Append(x.Indexer.Name).Append('(');
 10053
 10054                        for (var i = 0; i < x.Arguments.Count; i++)
 10055                            x.Arguments[i].ToCSharpString(i > 0 ? sb.Append(", ") : sb, EnclosedIn.AvoidParens, ref name
 10056                                lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode)
 10057
 10058                        return sb.Append(isStandardIndexer ? ']' : ')');
 10059                    }
 10060                case ExpressionType.Try:
 10061                    {
 10062                        var x = (TryExpression)e;
 10063                        lineIndent = sb.GetRealLineIndent(lineIndent);
 10064
 10065                        var returnsValue = e.Type != typeof(void);
 10066                        void PrintPart(Expression part, ref SmallList<NamedWithIndex, Stack4<NamedWithIndex>> named)
 10067                        {
 10068                            var incIndent = lineIndent + indentSpaces;
 10069                            if (part is BlockExpression pb)
 10070                                pb.BlockToCSharpString(sb, ref named,
 10071                                    incIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode, inTheLastBl
 10072                            else
 10073                            {
 10074                                sb.NewLineIndent(incIndent);
 10075                                var isReturnable = returnsValue && part.NodeType.IsReturnable() &&
 10076                                    // todo: @improve right now it is a hack - usually to Assign something means no retu
 10077                                    !part.NodeType.IsAssignNodeType();
 10078                                if (isReturnable)
 10079                                    sb.Append("return ");
 10080                                part.ToCSharpString(sb, EnclosedIn.AvoidParens, ref named,
 10081                                    incIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10082                                sb.AppendSemicolonOnce();
 10083                            }
 10084                        }
 10085
 10086                        sb.AppendNewLineOnce();
 10087
 10088                        var isTryFault = x.Fault != null;
 10089                        if (isTryFault)
 10090                        {
 10091                            sb.Append("var fault = 0; // emulating try-fault");
 10092                            sb.NewLineIndent(lineIndent);
 10093                        }
 10094
 10095                        sb.Append("try");
 10096                        sb.NewLineIndent(lineIndent).Append('{');
 10097                        PrintPart(x.Body, ref named);
 10098                        sb.NewLineIndent(lineIndent).Append('}');
 10099                        if (isTryFault)
 10100                            sb.NewLineIndent(lineIndent).Append("catch (Exception) when (fault++ != 0) {}");
 10101
 10102                        var handlers = x.Handlers;
 10103                        if (handlers != null && handlers.Count > 0)
 10104                        {
 10105                            for (var i = 0; i < handlers.Count; i++)
 10106                            {
 10107                                var h = handlers[i];
 10108                                sb.NewLineIndent(lineIndent).Append("catch (");
 10109                                var exTypeName = h.Test.ToCode(stripNamespace, printType);
 10110                                sb.Append(exTypeName);
 10111
 10112                                var hVar = h.Variable;
 10113                                if (hVar != null)
 10114                                    sb.Append(' ').AppendName(hVar, hVar.Name, hVar.Type.ToCode(stripNamespace, printTyp
 10115
 10116                                sb.Append(')');
 10117                                if (h.Filter != null)
 10118                                {
 10119                                    sb.Append("when (");
 10120                                    sb.NewLineIndent(lineIndent);
 10121                                    h.Filter.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10122                                        lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognize
 10123                                    sb.NewLineIndent(lineIndent).Append(')');
 10124                                }
 10125
 10126                                sb.NewLineIndent(lineIndent).Append('{');
 10127                                PrintPart(h.Body, ref named);
 10128                                sb.NewLineIndent(lineIndent).Append('}');
 10129                            }
 10130                        }
 10131
 10132                        var faultOrFinally = x.Fault ?? x.Finally;
 10133                        if (faultOrFinally != null)
 10134                        {
 10135                            sb.NewLineIndent(lineIndent).Append("finally");
 10136                            sb.NewLineIndent(lineIndent).Append('{');
 10137                            if (isTryFault) sb.Append("if (fault != 0) {");
 10138
 10139                            PrintPart(faultOrFinally, ref named);
 10140
 10141                            sb.NewLineIndent(lineIndent).Append('}');
 10142                            if (isTryFault) sb.Append('}');
 10143                        }
 10144                        return sb;
 10145                    }
 10146                case ExpressionType.Label:
 10147                    {
 10148                        // we don't output the default value and relying on the Goto Return `return` instead, otherwise 
 10149                        return sb.NewLineIndent(lineIndent).AppendLabelName(((LabelExpression)e).Target, ref named).Appe
 10150                    }
 10151                case ExpressionType.Goto:
 10152                    {
 10153                        var gt = (GotoExpression)e;
 10154                        if (gt.Kind == GotoExpressionKind.Return || gt.Value != null)
 10155                        {
 10156                            var gtValue = gt.Value;
 10157                            if (gtValue == null)
 10158                                return enclosedIn == EnclosedIn.Return ? sb.Append(";") : sb.Append("return;");
 10159
 10160                            var isReturnable = gtValue.NodeType.IsReturnable();
 10161                            if (isReturnable & enclosedIn != EnclosedIn.Return)
 10162                                sb.Append("return ");
 10163
 10164                            gtValue.ToCSharpString(sb, EnclosedIn.AvoidParens, ref named,
 10165                                lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10166
 10167                            if (isReturnable)
 10168                                sb.AppendSemicolonOnce();
 10169                            return sb;
 10170                        }
 10171                        return sb.Append("goto ").AppendLabelName(gt.Target, ref named);
 10172                    }
 10173                case ExpressionType.Switch:
 10174                    {
 10175                        var x = (SwitchExpression)e;
 10176
 10177                        lineIndent = sb.GetRealLineIndent(lineIndent);
 10178
 10179                        sb.Append("switch (");
 10180                        x.SwitchValue.ToCSharpString(sb, EnclosedIn.AvoidParens, ref named,
 10181                            lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10182                        sb.Append(')');
 10183                        sb.NewLineIndent(lineIndent).Append('{');
 10184
 10185                        var caseValueIndent = lineIndent + indentSpaces;
 10186                        var caseBodyIndent = caseValueIndent + indentSpaces;
 10187                        foreach (var cs in x.Cases)
 10188                        {
 10189                            foreach (var tv in cs.TestValues)
 10190                            {
 10191                                sb.NewLineIndent(caseValueIndent).Append("case ");
 10192                                tv.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10193                                    caseValueIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).Appen
 10194                            }
 10195
 10196                            sb.NewLineIndent(caseBodyIndent);
 10197                            var caseBody = cs.Body;
 10198                            if (enclosedIn == EnclosedIn.LambdaBody)
 10199                            {
 10200                                if (caseBody is BlockExpression bl)
 10201                                    bl.BlockToCSharpString(sb, ref named,
 10202                                        caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode, in
 10203                                else
 10204                                {
 10205                                    var bodyIn = caseBody.Type != typeof(void) ? EnclosedIn.Return : EnclosedIn.AvoidPar
 10206                                    caseBody.ToCSharpString(bodyIn == EnclosedIn.Return ? sb.Append("return ") : sb, bod
 10207                                        caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).Ap
 10208                                }
 10209                            }
 10210                            else
 10211                                caseBody.ToCSharpString(sb, enclosedIn, ref named,
 10212                                    caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).Append
 10213                        }
 10214
 10215                        if (x.DefaultBody != null)
 10216                        {
 10217                            var defaultBody = x.DefaultBody;
 10218                            sb.NewLineIndent(caseValueIndent).Append("default:");
 10219                            sb.NewLineIndent(caseBodyIndent);
 10220                            if (enclosedIn == EnclosedIn.LambdaBody)
 10221                            {
 10222                                if (defaultBody is BlockExpression bl)
 10223                                    bl.BlockToCSharpString(sb, ref named,
 10224                                        caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode, in
 10225                                else
 10226                                {
 10227                                    var bodyIn = defaultBody.Type != typeof(void) ? EnclosedIn.Return : EnclosedIn.Avoid
 10228                                    defaultBody.ToCSharpString(bodyIn == EnclosedIn.Return ? sb.Append("return ") : sb, 
 10229                                        caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).Ap
 10230                                }
 10231                            }
 10232                            else
 10233                                defaultBody.ToCSharpString(sb, enclosedIn, ref named,
 10234                                    caseBodyIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).Append
 10235                        }
 10236
 10237                        return sb.NewLineIndent(lineIndent).Append("}");
 10238                    }
 10239                case ExpressionType.Default:
 10240                    return e.Type == typeof(void)
 10241                            ? sb // `default(void)` does not make sense in the C#
 10242                            : NullConstantOrDefaultToCSharpString(e.Type, sb, enclosedIn, stripNamespace, printType);
 10243
 10244                case ExpressionType.TypeIs:
 10245                case ExpressionType.TypeEqual:
 10246                    {
 10247                        var x = (TypeBinaryExpression)e;
 10248                        sb.Append('(');
 10249                        // Use C# `is T` even for TypeEqual if the two are equivalent (this syntax is nicer)
 10250                        // IsSealed returns true for arrays, but arrays are cursed and don't behave like sealed classes 
 10251                        if (x.NodeType == ExpressionType.TypeIs || (x.TypeOperand.IsSealed && !x.TypeOperand.IsArray))
 10252                        {
 10253                            x.Expression.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10254                                lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10255                            sb.Append(" is ").Append(x.TypeOperand.ToCode(stripNamespace, printType));
 10256                        }
 10257                        else
 10258                        {
 10259                            x.Expression.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10260                                lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10261                            sb.Append(".GetType() == typeof(").Append(x.TypeOperand.ToCode(stripNamespace, printType)).A
 10262
 10263                        }
 10264                        return sb.Append(')');
 10265                    }
 10266                case ExpressionType.Coalesce:
 10267                    {
 10268                        var x = (BinaryExpression)e;
 10269                        x.Left.ToCSharpExpression(sb, EnclosedIn.ParensByDefault, ref named,
 10270                            false, lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10271                        sb.Append(" ?? ");
 10272                        x.Right.ToCSharpExpression(sb, EnclosedIn.ParensByDefault, ref named,
 10273                            false, lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10274                        return sb;
 10275                    }
 10276                case ExpressionType.Extension:
 10277                    {
 10278                        var reduced = e.Reduce(); // proceed with the reduced expression
 10279                        return reduced.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10280                            lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10281                    }
 10282                case ExpressionType.Dynamic:
 10283                case ExpressionType.RuntimeVariables:
 10284                case ExpressionType.DebugInfo:
 10285                case ExpressionType.Quote:
 10286                    {
 10287                        return sb.NewLineIndent(lineIndent).Append(NotSupportedExpression).Append(e.NodeType).NewLineInd
 10288                    }
 10289                default:
 10290                    {
 10291                        var avoidParens = AvoidParens(enclosedIn);
 10292
 10293                        var name = Enum.GetName(typeof(ExpressionType), e.NodeType);
 10294                        if (e is UnaryExpression u)
 10295                        {
 10296                            var op = u.Operand;
 10297                            switch (e.NodeType)
 10298                            {
 10299                                case ExpressionType.ArrayLength:
 10300                                    return op.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10301                                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode)
 10302                                        .Append(".Length");
 10303
 10304                                case ExpressionType.Not: // either the bool not or the binary not
 10305                                    return op.ToCSharpString(
 10306                                        e.Type == typeof(bool) ? sb.Append("!(") : sb.Append("~("), enclosedIn, ref name
 10307                                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode)
 10308                                        .Append(')');
 10309
 10310                                case ExpressionType.Convert:
 10311                                case ExpressionType.ConvertChecked:
 10312                                    if (e.Type == op.Type || e.Type == typeof(Enum) && op.Type.IsEnum)
 10313                                        return op.ToCSharpExpression(sb, EnclosedIn.AvoidParens, ref named,
 10314                                            false, lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToC
 10315
 10316                                    sb = avoidParens ? sb.Append('(') : sb.Append("((");
 10317                                    sb.Append(e.Type.ToCode(stripNamespace, printType));
 10318                                    sb.Append(')');
 10319                                    sb = op.ToCSharpExpression(sb, EnclosedIn.AvoidParens, ref named,
 10320                                        false, lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode)
 10321                                    return avoidParens ? sb : sb.Append(')');
 10322
 10323                                case ExpressionType.Decrement:
 10324                                case ExpressionType.Increment:
 10325                                    if (!avoidParens) sb.Append('(');
 10326                                    sb = op.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10327                                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10328                                    sb = e.NodeType == ExpressionType.Decrement ? sb.Append(" - 1") : sb.Append(" + 1");
 10329                                    if (!avoidParens) sb.Append(')');
 10330                                    return sb;
 10331
 10332                                case ExpressionType.Negate:
 10333                                case ExpressionType.NegateChecked:
 10334                                    if (!avoidParens) sb.Append('(');
 10335                                    op.ToCSharpString(sb.Append('-'), EnclosedIn.ParensByDefault, ref named,
 10336                                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10337                                    if (!avoidParens) sb.Append(')');
 10338                                    return sb;
 10339
 10340                                case ExpressionType.PostIncrementAssign:
 10341                                case ExpressionType.PreIncrementAssign:
 10342                                case ExpressionType.PostDecrementAssign:
 10343                                case ExpressionType.PreDecrementAssign:
 10344                                    if (!avoidParens) sb.Append('(');
 10345                                    sb = e.NodeType == ExpressionType.PreIncrementAssign ? sb.Append("++") : e.NodeType 
 10346                                    op.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10347                                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10348                                    sb = e.NodeType == ExpressionType.PostIncrementAssign ? sb.Append("++") : e.NodeType
 10349                                    if (!avoidParens) sb.Append(')');
 10350                                    return sb;
 10351
 10352                                case ExpressionType.IsTrue:
 10353                                    return op.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10354                                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).Append
 10355
 10356                                case ExpressionType.IsFalse:
 10357                                    return op.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10358                                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).Append
 10359
 10360                                case ExpressionType.TypeAs:
 10361                                case ExpressionType.TypeIs:
 10362                                    if (!avoidParens) sb.Append('(');
 10363                                    op.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10364                                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10365                                    sb = e.NodeType == ExpressionType.TypeAs ? sb.Append(" as ") : sb.Append(" is ");
 10366                                    sb.Append(e.Type.ToCode(stripNamespace, printType));
 10367                                    if (!avoidParens) sb.Append(')');
 10368                                    return sb;
 10369
 10370                                case ExpressionType.Throw:
 10371                                    return op is null ? sb.Append("throw") :
 10372                                        op.ToCSharpString(sb.Append("throw "), EnclosedIn.ParensByDefault, ref named,
 10373                                            lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10374
 10375                                case ExpressionType.Unbox: // output it as the cast
 10376                                    sb = avoidParens ? sb.Append("(") : sb.Append("((");
 10377                                    sb.Append(e.Type.ToCode(stripNamespace, printType)).Append(')');
 10378                                    op.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10379                                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10380                                    return avoidParens ? sb : sb.Append(')');
 10381
 10382                                default:
 10383                                    return sb.Append(e.ToString()); // falling back ro ToString as a closest to C# code 
 10384                            }
 10385                        }
 10386
 10387                        if (e is BinaryExpression b)
 10388                        {
 10389                            var nodeType = e.NodeType;
 10390                            if (nodeType == ExpressionType.ArrayIndex)
 10391                            {
 10392                                var arrInParens = b.Left.NodeType != ExpressionType.Parameter;
 10393                                if (arrInParens) sb.Append('(');
 10394                                b.Left.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10395                                    lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10396                                if (arrInParens) sb.Append(')');
 10397                                return b.Right.ToCSharpString(sb.Append("["), EnclosedIn.ParensByDefault, ref named,
 10398                                    lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).Append("]"
 10399                            }
 10400
 10401                            if (nodeType.IsAssignNodeType())
 10402                            {
 10403                                // todo: @perf handle the right part is condition with the blocks for If and/or Else, e.
 10404                                if (b.Right is BlockExpression rightBlock) // it is valid to assign the block and it is 
 10405                                {
 10406                                    sb.Append("// { The block result will be assigned to `")
 10407                                        .Append(b.Left.ToCSharpString(new StringBuilder(), EnclosedIn.ParensByDefault, r
 10408                                            lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode))
 10409                                        .Append('`');
 10410                                    rightBlock.BlockToCSharpString(sb, ref named,
 10411                                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode, false,
 10412                                    return sb.NewLineIndent(lineIndent).Append("// } end of block assignment");
 10413                                }
 10414
 10415                                b.Left.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10416                                    lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10417                                if (nodeType == ExpressionType.PowerAssign)
 10418                                {
 10419                                    sb.Append(" = System.Math.Pow(");
 10420                                    b.Left.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10421                                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).Append
 10422                                    return b.Right.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10423                                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).Append
 10424                                }
 10425
 10426                                sb.Append(OperatorToCSharpString(nodeType));
 10427
 10428                                if (b.Left is ParameterExpression leftParam && leftParam.IsByRef && !b.Right.IsConstantO
 10429                                    sb.Append("ref ");
 10430
 10431                                return b.Right.ToCSharpExpression(sb, EnclosedIn.AvoidParens, ref named,
 10432                                    false, lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10433                            }
 10434
 10435                            sb = !avoidParens ? sb.Append('(') : sb;
 10436                            b.Left.ToCSharpExpression(sb, EnclosedIn.ParensByDefault, ref named,
 10437                                false, lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10438
 10439                            if (nodeType == ExpressionType.Equal)
 10440                            {
 10441                                if (b.Right is ConstantExpression r && r.Value is bool rb && rb)
 10442                                    return sb;
 10443                                sb.Append(" == ");
 10444                            }
 10445                            else if (nodeType == ExpressionType.NotEqual)
 10446                            {
 10447                                if (b.Right is ConstantExpression r && r.Value is bool rb)
 10448                                    return rb ? sb.Append(" == false") : sb;
 10449                                sb.Append(" != ");
 10450                            }
 10451                            else
 10452                                sb.Append(OperatorToCSharpString(nodeType));
 10453
 10454                            b.Right.ToCSharpExpression(sb, EnclosedIn.ParensByDefault, ref named,
 10455                                false, lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10456                            return !avoidParens ? sb.Append(')') : sb;
 10457                        }
 10458
 10459                        return sb.Append(e.ToString()); // falling back ToString and hoping for the best
 10460                    }
 10461            }
 10462        }
 10463
 10464        private static bool AvoidParens(EnclosedIn enclosedIn) =>
 10465            enclosedIn == EnclosedIn.AvoidParens |
 10466            enclosedIn == EnclosedIn.LambdaBody |
 10467            enclosedIn == EnclosedIn.Block | // statement in a block don't need the parens as well
 10468            enclosedIn == EnclosedIn.Return;
 10469
 10470        private static StringBuilder ToCSharpBlock(this Expression expr, StringBuilder sb, ref SmallList<NamedWithIndex,
 10471            int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode no
 10472        {
 10473            sb.NewLineIndent(lineIndent).Append('{');
 10474            if (expr is BlockExpression fb)
 10475                fb.BlockToCSharpString(sb, ref named,
 10476                    lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode, inTheLastBl
 10477            else
 10478            {
 10479                sb.NewLineIndent(lineIndent + indentSpaces);
 10480                sb = expr?.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10481                    lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode) ?? sb.Appen
 10482                sb.AppendSemicolonOnce();
 10483            }
 10484            return sb.NewLineIndent(lineIndent).Append('}');
 10485        }
 10486
 10487        private static StringBuilder ToCSharpExpression(this Expression expr,
 10488            StringBuilder sb, EnclosedIn enclosedIn, ref SmallList<NamedWithIndex, Stack4<NamedWithIndex>> named, bool n
 10489            int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode no
 10490        {
 10491            if (!expr.NodeType.IsBlockLike())
 10492            {
 10493                if (!newLineExpr)
 10494                    return expr.ToCSharpString(sb, enclosedIn, ref named,
 10495                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10496
 10497                sb.NewLineIndent(lineIndent);
 10498                return expr.ToCSharpString(sb, enclosedIn, ref named,
 10499                    lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10500            }
 10501
 10502            InsertTopFFuncDefinitionOnce(sb);
 10503            sb.NewLineIndent(lineIndent).Append("__f(() => {");
 10504            if (expr is BlockExpression bl)
 10505                bl.BlockToCSharpString(sb, ref named,
 10506                    lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode, inTheLastBl
 10507            else
 10508            {
 10509                sb.NewLineIndent(lineIndent + indentSpaces);
 10510                if (expr != null)
 10511                    expr.ToCSharpString(sb, EnclosedIn.LambdaBody, ref named,
 10512                        lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10513                else
 10514                    sb.Append("null");
 10515
 10516            }
 10517            return sb.NewLineIndent(lineIndent).Append("})");
 10518        }
 10519
 10520        internal static StringBuilder AppendSemicolonOnce(this StringBuilder sb) =>
 10521            sb[sb.Length - 1] != ';' ? sb.Append(";") : sb;
 10522
 10523        internal static StringBuilder AppendNewLineOnce(this StringBuilder sb)
 10524        {
 10525            for (var end = sb.Length - 1; end >= 0; --end)
 10526            {
 10527                if (sb[end] == '\n')
 10528                    return sb; // return the unchanged sb when new line is already present
 10529                if (sb[end] != ' ') // skip spaces if any
 10530                    break;
 10531            }
 10532            return sb.Append(NewLine);
 10533        }
 10534
 10535        // Returns the number of consecutive spaces from the current position,
 10536        // or from the first non-space character to the prev newline.
 10537        // e.g. for `\n    foo.Bar = ` and for `\n    ` indent is 4
 10538        internal static int GetRealLineIndent(this StringBuilder sb, int defaultIndent)
 10539        {
 10540            var lastSpacePos = -1;
 10541            // go back from the last char in the builder
 10542            for (var pos = sb.Length - 1; pos >= 0; --pos)
 10543            {
 10544                var ch = sb[pos];
 10545                if (ch == '\n')
 10546                    return lastSpacePos == -1 ? defaultIndent : lastSpacePos - pos;
 10547
 10548                if (ch != ' ')
 10549                    lastSpacePos = -1; // reset space position when non-space char is found
 10550                else if (lastSpacePos == -1)
 10551                    lastSpacePos = pos; // set the last space position
 10552            }
 10553            return defaultIndent;
 10554        }
 10555
 10556        private const string NotSupportedExpression = "// NOT_SUPPORTED_EXPRESSION: ";
 10557
 10558        private static StringBuilder ToCSharpString(this IReadOnlyList<MemberBinding> bindings,
 10559            StringBuilder sb, EnclosedIn enclosedIn, ref SmallList<NamedWithIndex, Stack4<NamedWithIndex>> named,
 10560            int lineIndent = 0, bool stripNamespace = false, Func<Type, string, string> printType = null, int indentSpac
 10561        {
 10562            var count = bindings.Count;
 10563            for (var i = 0; i < count; i++)
 10564            {
 10565                var b = bindings[i];
 10566                sb.NewLineIndent(lineIndent);
 10567                sb.Append(b.Member.Name).Append(" = ");
 10568
 10569                if (b is MemberAssignment ma)
 10570                {
 10571                    ma.Expression.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref named,
 10572                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10573                }
 10574                else if (b is MemberMemberBinding mmb)
 10575                {
 10576                    sb.Append("{");
 10577                    mmb.Bindings.ToCSharpString(sb, enclosedIn, ref named,
 10578                        lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10579                    sb.NewLineIndent(lineIndent + indentSpaces).Append("}");
 10580                }
 10581                else if (b is MemberListBinding mlb)
 10582                {
 10583                    sb.Append("{");
 10584                    var elemInits = mlb.Initializers;
 10585                    var elemCount = elemInits.Count;
 10586                    for (var e = 0; e < elemCount; e++)
 10587                    {
 10588                        var args = elemInits[e].Arguments;
 10589                        sb.NewLineIndent(lineIndent + indentSpaces);
 10590                        var manyArgs = args.Count > 1;
 10591                        if (manyArgs)
 10592                            sb.Append("(");
 10593
 10594                        var n = 0;
 10595                        foreach (var arg in args)
 10596                            arg.ToCSharpString((++n > 1 ? sb.Append(", ") : sb), EnclosedIn.ParensByDefault, ref named,
 10597                                lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode)
 10598
 10599                        if (manyArgs)
 10600                            sb.Append(")");
 10601
 10602                        if (e < elemCount - 1)
 10603                            sb.Append(",");
 10604                    }
 10605                    sb.NewLineIndent(lineIndent + indentSpaces).Append("}");
 10606                }
 10607
 10608                // don't place comma after the last binding
 10609                if (i < count - 1)
 10610                    sb.Append(",");
 10611            }
 10612            return sb;
 10613        }
 10614
 10615        private static StringBuilder BlockToCSharpString(this BlockExpression b, StringBuilder sb,
 10616            ref SmallList<NamedWithIndex, Stack4<NamedWithIndex>> named,
 10617            int lineIndent = 0, bool stripNamespace = false, Func<Type, string, string> printType = null, int indentSpac
 10618            ObjectToCode notRecognizedToCode = null, bool inTheLastBlock = false, BinaryExpression blockResultAssignment
 10619            bool containerIgnoresResult = false // in case of the container is lambda which is the Action/void delegate 
 10620        )
 10621        {
 10622            var vars = b.Variables.AsList();
 10623            var exprs = b.Expressions;
 10624
 10625            // handling the special case, AutoMapper like using the tmp variable to reassign the property
 10626            if (vars.Count == 1 & exprs.Count == 2 &&
 10627                exprs[0] is BinaryExpression st0 && st0.NodeType == ExpressionType.Assign &&
 10628                exprs[1] is BinaryExpression st1 && st1.NodeType == ExpressionType.Assign &&
 10629                st0.Left == vars[0] && st1.Right == vars[0])
 10630                return Assign(st1.Left, st0.Right).ToCSharpString(sb.NewLineIndent(lineIndent),
 10631                    EnclosedIn.Block, ref named, lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCod
 10632                    .AppendSemicolonOnce();
 10633
 10634            foreach (var v in vars)
 10635            {
 10636                sb.NewLineIndent(lineIndent);
 10637                var vType = v.Type;
 10638                var vIsByRef = v.IsByRef;
 10639                var vNameSuffix = !vIsByRef ? "" : "__discard_init_by_ref";
 10640
 10641                var vTypeCode = vType.ToCode(stripNamespace, printType);
 10642                var vName = new StringBuilder().AppendName(v, v.Name + vNameSuffix, vTypeCode, ref named);
 10643                sb.Append(vTypeCode).Append(' ').Append(vName).Append(vType.IsValueType && !vType.IsNullable() ? " = def
 10644
 10645                if (vIsByRef)
 10646                    sb.Append(" ref var ").AppendName(v, v.Name, vTypeCode, ref named).Append(" = ref ").Append(vName).A
 10647            }
 10648
 10649            // we don't inline a single expression case because it can always go crazy with assignment, e.g. `var a; a =
 10650            for (var i = 0; i < exprs.Count - 1; i++)
 10651            {
 10652                var expr = exprs[i];
 10653
 10654                // this is basically the return pattern (see #237) so we don't care for the rest of the expressions
 10655                // Note (#300) the sentence above is slightly wrong because that may be a goto to this specific label, s
 10656                if (expr is GotoExpression gt && gt.Kind == GotoExpressionKind.Return &&
 10657                    exprs[i + 1] is LabelExpression label && label.Target == gt.Target)
 10658                {
 10659                    sb.NewLineIndent(lineIndent);
 10660                    if (gt.Value == null)
 10661                        sb.Append("return;");
 10662                    else
 10663                        gt.Value.ToCSharpString(sb.Append("return "),
 10664                            EnclosedIn.Return, ref named, lineIndent, stripNamespace, printType, indentSpaces, notRecogn
 10665                            .AppendSemicolonOnce();
 10666
 10667                    sb.NewLineIndent(lineIndent);
 10668                    sb.AppendLabelName(label.Target, ref named).Append(":;");
 10669
 10670                    if (label.DefaultValue == null)
 10671                        return sb.AppendLine(); // no return because we may have other expressions after label
 10672                    sb.NewLineIndent(lineIndent);
 10673                    sb.Append("return ");
 10674                    label.DefaultValue.ToCSharpString(sb, EnclosedIn.Return, ref named,
 10675                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10676                    return sb.AppendSemicolonOnce();
 10677                }
 10678
 10679                if (expr is BlockExpression bl)
 10680                {
 10681                    // Unrolling the block on the same vertical line
 10682                    bl.BlockToCSharpString(sb, ref named,
 10683                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode, inTheLastBlock: false)
 10684                }
 10685                else
 10686                {
 10687                    sb.NewLineIndent(lineIndent);
 10688                    expr.ToCSharpString(sb, EnclosedIn.Block, ref named,
 10689                        lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10690
 10691                    // Preventing the `};` kind of situation and separating the conditional block with empty line
 10692                    var nodeType = expr.NodeType;
 10693                    if (nodeType.IsBlockLikeOrConditional())
 10694                        sb.NewLineIndent(lineIndent);
 10695                    else if (nodeType != ExpressionType.Label & nodeType != ExpressionType.Default)
 10696                        sb.AppendSemicolonOnce();
 10697                }
 10698            }
 10699
 10700            var lastExpr = exprs[exprs.Count - 1];
 10701            if (lastExpr.NodeType == ExpressionType.Default && lastExpr.Type == typeof(void))
 10702                return sb;
 10703
 10704            if (lastExpr is BlockExpression lastBlock)
 10705                return lastBlock.BlockToCSharpString(sb, ref named,
 10706                    lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode,
 10707                    inTheLastBlock, // the last block is marked so if only it is itself in the last block
 10708                    blockResultAssignment);
 10709
 10710            // todo: @improve the label is already used by the Return GoTo we should skip it output here OR we need to r
 10711            if (lastExpr is LabelExpression) // keep the last label on the same vertical line
 10712            {
 10713                lastExpr.ToCSharpString(sb, EnclosedIn.Block, ref named,
 10714                    lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10715                if (inTheLastBlock)
 10716                    sb.AppendSemicolonOnce(); // the last label forms the invalid C#, so we need at least ';' at the end
 10717                return sb;
 10718            }
 10719
 10720            sb.NewLineIndent(lineIndent);
 10721            var enclosedIn = EnclosedIn.Block;
 10722            if (blockResultAssignment != null)
 10723            {
 10724                blockResultAssignment.Left.ToCSharpString(sb, enclosedIn, ref named,
 10725                    lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10726                if (blockResultAssignment.NodeType != ExpressionType.PowerAssign)
 10727                    sb.Append(OperatorToCSharpString(blockResultAssignment.NodeType));
 10728                else
 10729                {
 10730                    sb.Append(" = System.Math.Pow(");
 10731                    blockResultAssignment.Left.ToCSharpString(sb, enclosedIn, ref named,
 10732                        lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode).Append(", ");
 10733                }
 10734            }
 10735            else if (inTheLastBlock & !containerIgnoresResult &&
 10736                b.Type != typeof(void) && lastExpr.Type != typeof(void))
 10737            {
 10738                // A Trow may have the non void type, yes, so this check will avoid `return throw Ex` thingy, see #457, 
 10739                if (lastExpr.NodeType != ExpressionType.Throw &&
 10740                    // todo: @hack if the last expression is the Assignment BinaryExpression,
 10741                    // it is very doubtful that it is supposed to be returned result. I need to find a better indicator 
 10742                    !lastExpr.NodeType.IsAssignNodeType())
 10743                {
 10744                    enclosedIn = EnclosedIn.Return;
 10745                    sb.Append("return ");
 10746                }
 10747            }
 10748
 10749            if (lastExpr.NodeType.IsBlockLike() ||
 10750                lastExpr is DefaultExpression d && d.Type == typeof(void))
 10751            {
 10752                lastExpr.ToCSharpString(sb, EnclosedIn.Block, ref named,
 10753                    lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10754            }
 10755            else if (lastExpr.NodeType == ExpressionType.Assign && ((BinaryExpression)lastExpr).Right is BlockExpression
 10756            {
 10757                lastExpr.ToCSharpString(sb, EnclosedIn.Block, ref named,
 10758                    lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10759                if (enclosedIn == EnclosedIn.Return)
 10760                    sb.AppendSemicolonOnce();
 10761            }
 10762            else
 10763            {
 10764                lastExpr.ToCSharpString(sb, enclosedIn, ref named,
 10765                    lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode);
 10766                sb = blockResultAssignment?.NodeType == ExpressionType.PowerAssign ? sb.Append(')') : sb;
 10767                if (lastExpr.NodeType != ExpressionType.Conditional || lastExpr.Type != typeof(void))
 10768                    sb.AppendSemicolonOnce();
 10769            }
 10770            return sb;
 10771        }
 10772
 10773        private static string OperatorToCSharpString(ExpressionType nodeType) =>
 10774            nodeType switch
 10775            {
 10776                ExpressionType.And => " & ",
 10777                ExpressionType.AndAssign => " &= ",
 10778                ExpressionType.AndAlso => " && ",
 10779                ExpressionType.Or => " | ",
 10780                ExpressionType.OrAssign => " |= ",
 10781                ExpressionType.OrElse => " || ",
 10782                ExpressionType.GreaterThan => " > ",
 10783                ExpressionType.GreaterThanOrEqual => " >= ",
 10784                ExpressionType.LessThan => " < ",
 10785                ExpressionType.LessThanOrEqual => " <= ",
 10786                ExpressionType.Equal => " == ",
 10787                ExpressionType.NotEqual => " != ",
 10788                ExpressionType.Add => " + ",
 10789                ExpressionType.AddChecked => " + ",
 10790                ExpressionType.AddAssign => " += ",
 10791                ExpressionType.AddAssignChecked => " += ",
 10792                ExpressionType.Subtract => " - ",
 10793                ExpressionType.SubtractChecked => " - ",
 10794                ExpressionType.SubtractAssign => " -= ",
 10795                ExpressionType.SubtractAssignChecked => " -= ",
 10796                ExpressionType.Assign => " = ",
 10797                ExpressionType.ExclusiveOr => " ^ ",
 10798                ExpressionType.ExclusiveOrAssign => " ^= ",
 10799                ExpressionType.LeftShift => " << ",
 10800                ExpressionType.LeftShiftAssign => " <<= ",
 10801                ExpressionType.RightShift => " >> ",
 10802                ExpressionType.RightShiftAssign => " >>= ",
 10803                ExpressionType.Modulo => " % ",
 10804                ExpressionType.ModuloAssign => " %= ",
 10805                ExpressionType.Multiply => " * ",
 10806                ExpressionType.MultiplyChecked => " * ",
 10807                ExpressionType.MultiplyAssign => " *= ",
 10808                ExpressionType.MultiplyAssignChecked => " *= ",
 10809                ExpressionType.Divide => " / ",
 10810                ExpressionType.DivideAssign => " /= ",
 10811                _ => "???" // todo: @unclear wanna be good
 10812            };
 10813
 10814    }
 10815
 10816    [RequiresUnreferencedCode(Trimming.Message)]
 10817    internal static class CodePrinter
 10818    {
 010819        public static readonly Func<Type, string, string> PrintTypeStripOuterClasses = (type, name) =>
 010820        {
 010821            if (!type.IsNested)
 010822                return name;
 010823            var index = name.LastIndexOf('.');
 010824            return index == -1 ? name : name.Substring(index + 1);
 010825        };
 10826
 10827        public static StringBuilder AppendTypeOf(this StringBuilder sb, Type type,
 10828            bool stripNamespace = false, Func<Type, string, string> printType = null, bool printGenericTypeArgs = false)
 010829        {
 010830            if (type == null)
 010831                return sb.Append("null");
 010832            sb.Append("typeof(").Append(type.ToCode(stripNamespace, printType, printGenericTypeArgs)).Append(')');
 010833            return type.IsByRef ? sb.Append(".MakeByRefType()") : sb;
 010834        }
 10835
 10836        public static StringBuilder AppendTypeOfList(this StringBuilder sb, Type[] types,
 10837            bool stripNamespace = false, Func<Type, string, string> printType = null, bool printGenericTypeArgs = false)
 010838        {
 010839            for (var i = 0; i < types.Length; i++)
 010840                (i > 0 ? sb.Append(", ") : sb).AppendTypeOf(types[i], stripNamespace, printType, printGenericTypeArgs);
 010841            return sb;
 010842        }
 10843
 10844        internal static StringBuilder AppendMember(this StringBuilder sb, MemberInfo member,
 10845            bool stripNamespace = false, Func<Type, string, string> printType = null) =>
 010846            member is FieldInfo f
 010847                ? sb.AppendField(f, stripNamespace, printType)
 010848                : sb.AppendProperty((PropertyInfo)member, stripNamespace, printType);
 10849
 10850        internal static StringBuilder AppendField(this StringBuilder sb, FieldInfo field,
 10851            bool stripNamespace = false, Func<Type, string, string> printType = null) =>
 010852            sb.AppendTypeOf(field.DeclaringType, stripNamespace, printType)
 010853              .Append(".GetTypeInfo().GetDeclaredField(\"").Append(field.Name).Append("\")");
 10854
 10855        internal static StringBuilder AppendProperty(this StringBuilder sb, PropertyInfo property,
 10856            bool stripNamespace = false, Func<Type, string, string> printType = null) =>
 010857            sb.AppendTypeOf(property.DeclaringType, stripNamespace, printType)
 010858              .Append(".GetTypeInfo().GetDeclaredProperty(\"").Append(property.Name).Append("\")");
 10859
 10860        internal static StringBuilder AppendEnum<TEnum>(this StringBuilder sb, TEnum value,
 10861            bool stripNamespace = false, Func<Type, string, string> printType = null) =>
 010862            sb.Append(typeof(TEnum).ToCode(stripNamespace, printType)).Append('.')
 010863              .Append(Enum.GetName(typeof(TEnum), value));
 10864
 10865        private const string _nonPubStatMethods = "BindingFlags.NonPublic|BindingFlags.Static";
 10866        private const string _nonPubInstMethods = "BindingFlags.NonPublic|BindingFlags.Instance";
 10867
 10868        public static StringBuilder AppendMethod(this StringBuilder sb, MethodInfo method,
 10869            bool stripNamespace = false, Func<Type, string, string> printType = null)
 010870        {
 010871            if (method == null)
 010872                return sb.Append("null");
 10873
 010874            sb.AppendTypeOf(method.DeclaringType, stripNamespace, printType);
 010875            sb.Append(".GetMethods(");
 10876
 010877            if (!method.IsPublic)
 010878                sb.Append(method.IsStatic ? _nonPubStatMethods : _nonPubInstMethods);
 10879
 010880            var mp = method.GetParameters();
 010881            if (!method.IsGenericMethod)
 010882            {
 010883                sb.Append(").Single(x => !x.IsGenericMethod && x.Name == \"").Append(method.Name).Append("\" && ");
 010884                return mp.Length == 0
 010885                    ? sb.Append("x.GetParameters().Length == 0)")
 010886                    : sb.Append("x.GetParameters().Select(y => y.ParameterType).SequenceEqual(new[] { ")
 010887                        .AppendTypeOfList(mp.Select(x => x.ParameterType).ToArray(), stripNamespace, printType)
 010888                        .Append(" }))");
 10889            }
 10890
 010891            var tp = method.GetGenericArguments();
 010892            sb.Append(").Where(x => x.IsGenericMethod && x.Name == \"").Append(method.Name).Append("\" && ");
 010893            if (mp.Length == 0)
 010894            {
 010895                sb.Append("x.GetParameters().Length == 0 && x.GetGenericArguments().Length == ").Append(tp.Length);
 010896                sb.Append(").Select(x => x.IsGenericMethodDefinition ? x.MakeGenericMethod(").AppendTypeOfList(tp, strip
 010897                return sb.Append(") : x).Single()");
 10898            }
 10899
 010900            sb.Append("x.GetGenericArguments().Length == ").Append(tp.Length);
 010901            sb.Append(").Select(x => x.IsGenericMethodDefinition ? x.MakeGenericMethod(").AppendTypeOfList(tp, stripName
 010902            sb.Append(") : x).Single(x => x.GetParameters().Select(y => y.ParameterType).SequenceEqual(new[] { ");
 010903            sb.AppendTypeOfList(mp.Select(x => x.ParameterType).ToArray(), stripNamespace, printType);
 010904            return sb.Append(" }))");
 010905        }
 10906
 10907        /// <summary>Named with index indeed</summary>
 10908        internal struct NamedWithIndex
 10909        {
 10910            /// <summary>Named</summary>
 10911            public object Named;
 10912            /// <summary>Provides an unique suffix for the same named things</summary>
 10913            public int Index;
 10914        }
 10915
 10916        internal static StringBuilder AppendName(this StringBuilder sb, object parOrTarget, string name, string typeCode
 10917            ref SmallList<NamedWithIndex, Stack4<NamedWithIndex>> named,
 10918            int noNameIndex = 0)
 010919        {
 010920            var nameIndex = 0;
 010921            if (noNameIndex == 0)
 010922            {
 010923                var found = false;
 010924                foreach (var n in named)
 010925                {
 010926                    if (found = ReferenceEquals(n.Named, parOrTarget))
 010927                    {
 010928                        nameIndex = n.Index;
 010929                        break;
 10930                    }
 010931                    if (n.Named is ParameterExpression pe1 && parOrTarget is ParameterExpression pe2 && pe1.Name == pe2.
 010932                        n.Named is LabelTarget lt1 && parOrTarget is LabelTarget lt2 && lt1.Name == lt2.Name)
 010933                        ++nameIndex;
 010934                }
 010935                if (!found)
 010936                    named.Add(new NamedWithIndex { Named = parOrTarget, Index = nameIndex });
 010937                noNameIndex = nameIndex;
 010938            }
 10939
 010940            if (!string.IsNullOrWhiteSpace(name))
 010941            {
 010942                sb.Append(name);
 010943                return nameIndex == 0 ? sb : sb.Append('_').Append(nameIndex);
 10944            }
 010945            var validTypeIdent = typeCode
 010946                .Replace('.', '_')
 010947                .Replace('<', '_')
 010948                .Replace('>', '_')
 010949                .Replace(", ", "_")
 010950                .Replace("?", "")
 010951                .Replace("[]", "_arr")
 010952                .ToLowerInvariant();
 10953
 010954            return sb.Append(validTypeIdent).Append('_').Append(noNameIndex);
 010955        }
 10956
 10957        internal static StringBuilder AppendLabelName(this StringBuilder sb, LabelTarget target,
 10958            ref SmallList<NamedWithIndex, Stack4<NamedWithIndex>> named) =>
 010959            sb.AppendName(target, target.Name, target.Type.ToCode(stripNamespace: true), ref named);
 10960
 10961        /// <summary>Returns the standard name (alias) for the well-known primitive type, e.g. Int16 -> short</summary>
 10962        public static string GetPrimitiveTypeNameAliasOrNull(this Type type) =>
 798210963            Type.GetTypeCode(type) switch
 798210964            {
 410965                TypeCode.Byte => "byte",
 410966                TypeCode.SByte => "sbyte",
 410967                TypeCode.Int16 => "short",
 17810968                TypeCode.Int32 => "int",
 9110969                TypeCode.Int64 => "long",
 410970                TypeCode.UInt16 => "ushort",
 410971                TypeCode.UInt32 => "uint",
 410972                TypeCode.UInt64 => "ulong",
 410973                TypeCode.Single => "float",
 410974                TypeCode.Double => "double",
 73810975                TypeCode.Boolean => "bool",
 28710976                TypeCode.Char => "char",
 19910977                TypeCode.String => "string",
 645710978                _ => type == typeof(void) ? "void" :
 645710979                    type == typeof(object) ? "object" :
 645710980                    null
 798210981            };
 10982
 10983        // todo: @simplify add `addTypeof = false` or use `AppendTypeOf` generally
 10984        /// <summary>Converts the <paramref name="type"/> into the proper C# representation.</summary>
 10985        public static string ToCode(this Type type,
 10986            bool stripNamespace = false, Func<Type, string, string> printType = null, bool printGenericTypeArgs = false)
 799810987        {
 799810988            if (type == null)
 010989                return "null";
 10990
 799810991            if (type.IsGenericParameter)
 010992                return !printGenericTypeArgs ? string.Empty : (printType?.Invoke(type, type.Name) ?? type.Name);
 10993
 799810994            if (Nullable.GetUnderlyingType(type) is Type nullableElementType && !type.IsGenericTypeDefinition)
 1610995            {
 1610996                var result = nullableElementType.ToCode(stripNamespace, printType, printGenericTypeArgs) + "?";
 1610997                return printType?.Invoke(type, result) ?? result;
 10998            }
 10999
 798211000            Type arrayType = null;
 798211001            if (type.IsArray)
 17411002            {
 11003                // store the original type for the later and process its element type further here
 17411004                arrayType = type;
 17411005                type = type.GetElementType();
 17411006            }
 11007
 798211008            var buildInTypeString = type.GetPrimitiveTypeNameAliasOrNull();
 798211009            if (buildInTypeString != null)
 205111010            {
 205111011                if (arrayType != null)
 16611012                    buildInTypeString += "[]";
 205111013                return printType?.Invoke(arrayType ?? type, buildInTypeString) ?? buildInTypeString;
 11014            }
 11015
 593111016            var parentCount = 0;
 1222011017            for (var ti = type.GetTypeInfo(); ti.IsNested; ti = ti.DeclaringType.GetTypeInfo())
 17911018                ++parentCount;
 11019
 593111020            Type[] parentTypes = null;
 593111021            if (parentCount > 0)
 17911022            {
 17911023                parentTypes = new Type[parentCount];
 17911024                var pt = type.DeclaringType;
 89511025                for (var i = 0; i < parentTypes.Length; i++, pt = pt.DeclaringType)
 17911026                    parentTypes[i] = pt;
 17911027            }
 11028
 593111029            var typeInfo = type.GetTypeInfo();
 593111030            Type[] typeArgs = null;
 593111031            var isTypeClosedGeneric = false;
 593111032            if (type.IsGenericType)
 77811033            {
 77811034                isTypeClosedGeneric = !typeInfo.IsGenericTypeDefinition;
 77811035                typeArgs = isTypeClosedGeneric ? typeInfo.GenericTypeArguments : typeInfo.GenericTypeParameters;
 77811036            }
 11037
 593111038            var typeArgsConsumedByParentsCount = 0;
 593111039            var s = new StringBuilder();
 593111040            if (!stripNamespace && !string.IsNullOrEmpty(type.Namespace)) // for the auto-generated classes Namespace ma
 011041                s.Append(type.Namespace).Append('.');
 11042
 593111043            if (parentTypes != null)
 17911044            {
 71611045                for (var p = parentTypes.Length - 1; p >= 0; --p)
 17911046                {
 17911047                    var parentType = parentTypes[p];
 17911048                    if (!parentType.IsGenericType)
 16611049                    {
 16611050                        s.Append(parentType.Name).Append('.');
 16611051                    }
 11052                    else
 1311053                    {
 1311054                        var parentTypeInfo = parentType.GetTypeInfo();
 1311055                        Type[] parentTypeArgs = null;
 1311056                        if (parentTypeInfo.IsGenericTypeDefinition)
 1311057                        {
 1311058                            parentTypeArgs = parentTypeInfo.GenericTypeParameters;
 11059
 11060                            // replace the open parent args with the closed child args,
 11061                            // and close the parent
 1311062                            if (isTypeClosedGeneric)
 5211063                                for (var t = 0; t < parentTypeArgs.Length; ++t)
 1311064                                    parentTypeArgs[t] = typeArgs[t];
 11065
 1311066                            var parentTypeArgCount = parentTypeArgs.Length;
 1311067                            if (typeArgsConsumedByParentsCount > 0)
 011068                            {
 011069                                int ownArgCount = parentTypeArgCount - typeArgsConsumedByParentsCount;
 011070                                if (ownArgCount == 0)
 011071                                    parentTypeArgs = null;
 11072                                else
 011073                                {
 011074                                    var ownArgs = new Type[ownArgCount];
 011075                                    for (var a = 0; a < ownArgs.Length; ++a)
 011076                                        ownArgs[a] = parentTypeArgs[a + typeArgsConsumedByParentsCount];
 011077                                    parentTypeArgs = ownArgs;
 011078                                }
 011079                            }
 1311080                            typeArgsConsumedByParentsCount = parentTypeArgCount;
 1311081                        }
 11082                        else
 011083                        {
 011084                            parentTypeArgs = parentTypeInfo.GenericTypeArguments;
 011085                        }
 11086
 1311087                        var parentTickIndex = parentType.Name.IndexOf('`');
 1311088                        s.Append(parentType.Name.Substring(0, parentTickIndex));
 11089
 11090                        // The owned parentTypeArgs maybe empty because all args are defined in the parent's parents
 1311091                        if (parentTypeArgs?.Length > 0)
 1311092                        {
 1311093                            s.Append('<');
 5211094                            for (var t = 0; t < parentTypeArgs.Length; ++t)
 1311095                                (t == 0 ? s : s.Append(", ")).Append(parentTypeArgs[t].ToCode(stripNamespace, printType,
 1311096                            s.Append('>');
 1311097                        }
 1311098                        s.Append('.');
 1311099                    }
 17911100                }
 17911101            }
 593111102            var name = type.Name.TrimStart('<', '>').TrimEnd('&');
 11103
 593111104            if (typeArgs != null && typeArgsConsumedByParentsCount < typeArgs.Length)
 76511105            {
 76511106                var tickIndex = name.IndexOf('`');
 76511107                s.Append(name.Substring(0, tickIndex)).Append('<');
 414411108                for (var i = 0; i < typeArgs.Length - typeArgsConsumedByParentsCount; ++i)
 130711109                    (i == 0 ? s : s.Append(", ")).Append(typeArgs[i + typeArgsConsumedByParentsCount].ToCode(stripNamesp
 76511110                s.Append('>');
 76511111            }
 11112            else
 516611113            {
 516611114                s.Append(name);
 516611115            }
 11116
 593111117            if (arrayType != null)
 811118                s.Append("[]");
 11119
 593111120            return printType?.Invoke(arrayType ?? type, s.ToString()) ?? s.ToString();
 799811121        }
 11122
 11123        /// <summary>Prints valid C# Boolean</summary>
 011124        public static string ToCode(this bool x) => x ? "true" : "false";
 11125
 11126        /// <summary>Prints valid C# String escaping the things</summary>
 11127        public static string ToCode(this string x) =>
 011128            x == null ? "null"
 011129                : $"\"{x.Replace("\"", "\\\"").Replace("\r", "\\r").Replace("\n", "\\n")}\"";
 11130
 011131        private static readonly char[] _enumValueSeparators = new[] { ',', ' ' };
 11132
 11133        /// <summary>Prints valid C# Enum literal</summary>
 11134        public static string ToEnumValueCode(this Type enumType, object x,
 11135            bool stripNamespace = false, Func<Type, string, string> printType = null)
 011136        {
 011137            var typeStr = enumType.ToCode(stripNamespace, printType);
 011138            var valueStr = x.ToString();
 011139            var flags = valueStr.Split(_enumValueSeparators, StringSplitOptions.RemoveEmptyEntries);
 011140            if (flags.Length == 1)
 011141            {
 011142                if (int.TryParse(valueStr, out _))
 011143                    return "(" + typeStr + ")" + valueStr;
 011144                return typeStr + "." + valueStr;
 11145            }
 011146            var orTypeDot = "|" + typeStr + ".";
 011147            return typeStr + "." + string.Join(orTypeDot, flags);
 011148        }
 11149
 11150        private static Type[] GetGenericTypeParametersOrArguments(this TypeInfo typeInfo) =>
 011151            typeInfo.IsGenericTypeDefinition ? typeInfo.GenericTypeParameters : typeInfo.GenericTypeArguments;
 11152
 11153        /// <summary>Custom handler for output the object in valid C#.
 11154        /// Note, the `printGenericTypeArgs` is excluded because it cannot be a open-generic object.
 11155        /// This handler is also used to allow user to fully control a Constant expression output</summary>
 11156        internal delegate string ObjectToCode(object x, bool stripNamespace = false, Func<Type, string, string> printTyp
 11157
 11158        /// <summary>Outputs the `default(Type)` for the unknown constant with the comment message</summary>
 011159        public static readonly ObjectToCode DefaultNotRecognizedToCode = (x, stripNamespace, printType) =>
 011160        {
 011161            var t = x.GetType();
 011162            var isCompGen = t.IsCompilerGenerated();
 011163            var typeCs = x.GetType().ToCode(stripNamespace, printType);
 011164            return $"default({typeCs})/*NOTE: Provide the non-default value for the Constant{(isCompGen ? " of compiler-
 011165        };
 11166
 11167        /// <summary>Prints many code items as the array initializer.</summary>
 11168        public static string ToCommaSeparatedCode(this IEnumerable items, ObjectToCode notRecognizedToCode,
 11169            bool stripNamespace = false, Func<Type, string, string> printType = null)
 011170        {
 011171            var s = new StringBuilder();
 011172            var first = true;
 011173            foreach (var item in items)
 011174            {
 011175                if (!first)
 011176                    s.Append(", ");
 011177                first = false;
 011178                s.Append(item.ToCode(notRecognizedToCode, stripNamespace, printType));
 011179            }
 011180            return s.ToString();
 011181        }
 11182
 11183        /// <summary>Prints many code items as array initializer.</summary>
 11184        public static string ToArrayInitializerCode(this IEnumerable items, Type itemType, ObjectToCode notRecognizedToC
 11185            bool stripNamespace = false, Func<Type, string, string> printType = null)
 011186        {
 011187            var s = new StringBuilder("new ");
 11188            // todo: @simplify should we avoid type for the `new Type` because the values also will include the type?
 011189            s.Append(itemType.ToCode(stripNamespace, printType));
 011190            s.Append("[]{");
 011191            s.Append(items.ToCommaSeparatedCode(notRecognizedToCode, stripNamespace, printType));
 011192            s.Append('}');
 011193            return s.ToString();
 011194        }
 11195
 011196        private static readonly Type[] TypesImplementedByArray =
 011197            typeof(object[]).GetInterfaces().Where(t => t.GetTypeInfo().IsGenericType).Select(t => t.GetGenericTypeDefin
 11198
 11199        // todo: @simplify convert to using StringBuilder and simplify usage call-sites, or ADD the method
 11200        // todo: @simplify add `addTypeof = false`
 11201        /// <summary>
 11202        /// Prints a valid C# for known <paramref name="x"/>,
 11203        /// otherwise uses passed <paramref name="notRecognizedToCode"/> or falls back to `ToString()`.
 11204        /// </summary>
 11205        [System.Diagnostics.CodeAnalysis.RequiresUnreferencedCode(Trimming.Message)]
 11206        public static string ToCode(this object x,
 11207            ObjectToCode notRecognizedToCode = null, bool stripNamespace = false, Func<Type, string, string> printType =
 011208        {
 011209            if (x == null)
 011210                return "null";
 11211
 011212            if (x is bool b)
 011213                return b.ToCode();
 11214
 011215            if (x is int i)
 011216                return i.ToString();
 11217
 011218            if (x is double d)
 011219                return d.ToString();
 11220
 011221            if (x is string s)
 011222                return s.ToCode();
 11223
 011224            if (x is char c)
 011225                return "'" + c + "'";
 11226
 011227            if (x is Decimal m)
 011228                return $"{m}m";
 11229
 011230            if (x is Type t)
 011231                return t.ToCode(stripNamespace, printType);
 11232
 011233            if (x is Guid guid)
 011234                return "Guid.Parse(" + guid.ToString().ToCode() + ")";
 11235
 011236            if (x is DateTime date)
 011237                return "DateTime.Parse(" + date.ToString().ToCode() + ")";
 11238
 011239            if (x is TimeSpan time)
 011240                return "TimeSpan.Parse(" + time.ToString().ToCode() + ")";
 11241
 011242            var xType = x.GetType();
 011243            var xTypeInfo = xType.GetTypeInfo();
 11244
 11245            // check if item is implemented by array and then use the array initializer only for these types,
 11246            // otherwise we may produce the array initializer but it will be incompatible with e.g. `List<T>`
 011247            if (xTypeInfo.IsArray ||
 011248                xTypeInfo.IsGenericType && TypesImplementedByArray.Contains(xType.GetGenericTypeDefinition()))
 011249            {
 011250                var elemType = xTypeInfo.IsArray
 011251                    ? xTypeInfo.GetElementType()
 011252                    : xTypeInfo.GetGenericTypeParametersOrArguments().GetFirst();
 011253                if (elemType != null && elemType != xType) // avoid self recurring types e.g. `class A : IEnumerable<A>`
 011254                    return ((IEnumerable)x).ToArrayInitializerCode(elemType, notRecognizedToCode, stripNamespace, printT
 011255            }
 11256
 11257            // unwrap the Nullable struct
 011258            if (xTypeInfo.IsGenericType && xTypeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))
 011259            {
 011260                xType = xTypeInfo.GetElementType();
 011261                xTypeInfo = xType.GetTypeInfo();
 011262            }
 11263
 011264            if (xTypeInfo.IsEnum)
 011265                return x.GetType().ToEnumValueCode(x, stripNamespace, printType);
 11266
 011267            if (xTypeInfo.IsPrimitive) // output the primitive casted to the type
 011268                return "(" + x.GetType().ToCode(true, null) + ")" + x.ToString();
 11269
 011270            return notRecognizedToCode?.Invoke(x, stripNamespace, printType) ?? x.ToString();
 011271        }
 11272
 11273        internal static StringBuilder NewLineIndent(this StringBuilder sb, int lineIndent)
 011274        {
 011275            var originalLength = sb.Length;
 011276            sb.AppendNewLineOnce();
 011277            return originalLength == sb.Length ? sb : sb.Append(' ', lineIndent);
 011278        }
 11279
 11280        internal static StringBuilder NewLineIndentExpr(this StringBuilder sb,
 11281            Expression expr, List<ParameterExpression> paramsExprs, List<Expression> uniqueExprs, List<LabelTarget> lts,
 11282            int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode no
 011283        {
 011284            sb.NewLineIndent(lineIndent);
 011285            return expr?.ToExpressionString(sb, paramsExprs, uniqueExprs, lts,
 011286                lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode) ?? sb.Append("n
 011287        }
 11288
 11289        internal static StringBuilder NewLineIndentArgumentExprs<T>(this StringBuilder sb, IReadOnlyList<T> exprs,
 11290            List<ParameterExpression> paramsExprs, List<Expression> uniqueExprs, List<LabelTarget> lts,
 11291            int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode no
 11292            where T : Expression
 011293        {
 011294            if (exprs.Count == 0)
 011295                return sb.Append(" new ").Append(typeof(T).ToCode(true)).Append("[0]");
 011296            for (var i = 0; i < exprs.Count; i++)
 011297                (i > 0 ? sb.Append(", ") : sb).NewLineIndentExpr(exprs[i],
 011298                    paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToC
 011299            return sb;
 011300        }
 11301
 11302        // todo: @improve figure how to avoid the duplication with the method above IReadOnlyList<T> exprs
 11303        internal static StringBuilder NewLineIndentArgumentExprs<T>(this StringBuilder sb, SmallList<T, Stack2<T>> exprs
 11304            List<ParameterExpression> paramsExprs, List<Expression> uniqueExprs, List<LabelTarget> lts,
 11305            int lineIndent, bool stripNamespace, Func<Type, string, string> printType, int indentSpaces, ObjectToCode no
 11306            where T : Expression
 011307        {
 011308            if (exprs.Count == 0)
 011309                return sb.Append(" new ").Append(typeof(T).ToCode(true)).Append("[0]");
 011310            for (var i = 0; i < exprs.Count; i++)
 011311                (i > 0 ? sb.Append(", ") : sb).NewLineIndentExpr(exprs.GetSurePresentItemRef(i),
 011312                    paramsExprs, uniqueExprs, lts, lineIndent, stripNamespace, printType, indentSpaces, notRecognizedToC
 011313            return sb;
 011314        }
 11315
 11316        /// <summary>Helper method to find the number of lambdas in the C# code string</summary>
 11317        public static int CountLambdas(string code)
 011318        {
 011319            int lambdaCount = 0, lambdaIndex = 0;
 011320            while (true)
 011321            {
 011322                lambdaIndex = code.IndexOf("=>", lambdaIndex + 2);
 011323                if (lambdaIndex == -1)
 011324                    break;
 011325                ++lambdaCount;
 011326            }
 011327            return lambdaCount;
 011328        }
 11329    }
 11330
 11331    internal static class FecHelpers
 11332    {
 11333        public static int GetFirstIndex<T, TEq>(this IReadOnlyList<T> source, T item, TEq eq = default)
 11334            where TEq : struct, IEq<T>
 11335        {
 11336            if (source.Count != 0)
 11337                for (var i = 0; i < source.Count; ++i)
 11338                    if (eq.Equals(source[i], item))
 11339                        return i;
 11340            return -1;
 11341        }
 11342
 11343        [MethodImpl((MethodImplOptions)256)]
 11344        public static T GetArgument<T>(this IReadOnlyList<T> source, int index) => source[index];
 11345
 11346        [MethodImpl((MethodImplOptions)256)]
 11347        public static ParameterExpression GetParameter(this IReadOnlyList<PE> source, int index) => source[index];
 11348
 11349#if LIGHT_EXPRESSION
 11350        public static IReadOnlyList<PE> ToReadOnlyList(this IParameterProvider source)
 11351        {
 11352            var count = source.ParameterCount;
 11353            var ps = new ParameterExpression[count];
 11354            for (var i = 0; i < count; ++i)
 11355                ps[i] = source.GetParameter(i);
 11356            return ps;
 11357        }
 11358
 11359        public static int GetCount(this IParameterProvider p) => p.ParameterCount;
 11360#else
 11361        public static IReadOnlyList<PE> ToReadOnlyList(this IReadOnlyList<PE> source) => source;
 11362
 11363        public static int GetCount(this IReadOnlyList<PE> p) => p.Count;
 11364#endif
 11365
 11366#if SUPPORTS_ARGUMENT_PROVIDER
 11367        public static int GetCount(this IArgumentProvider p) => p.ArgumentCount;
 11368#else
 11369        public static int GetCount(this IReadOnlyList<Expression> p) => p.Count;
 11370#endif
 11371    }
 11372
 11373    internal static class Trimming
 11374    {
 11375        public const string Message = "FastExpressionCompiler is not supported in trimming scenarios.";
 11376    }
 11377}
 11378
 11379#if !NET5_0_OR_GREATER
 11380namespace System.Diagnostics.CodeAnalysis
 11381{
 11382    [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
 11383    internal sealed class UnconditionalSuppressMessageAttribute : Attribute
 11384    {
 11385        public string Category { get; }
 11386        public string CheckId { get; }
 11387        public string Justification { get; set; }
 11388        public UnconditionalSuppressMessageAttribute(string category, string checkId)
 11389        {
 11390            Category = category;
 11391            CheckId = checkId;
 11392        }
 11393    }
 11394
 11395    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Class, Inherited = false)]
 11396    internal sealed class RequiresUnreferencedCodeAttribute : Attribute
 11397    {
 11398        public string Message { get; }
 11399        public RequiresUnreferencedCodeAttribute(string message) => Message = message;
 11400    }
 11401
 11402    [AttributeUsage(
 11403        AttributeTargets.Field | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter |
 11404        AttributeTargets.Parameter | AttributeTargets.Property | AttributeTargets.Method |
 11405        AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Struct,
 11406        Inherited = false)]
 11407    internal sealed class DynamicallyAccessedMembersAttribute : Attribute
 11408    {
 11409        public DynamicallyAccessedMembersAttribute(DynamicallyAccessedMemberTypes memberTypes) { }
 11410    }
 11411
 11412    [Flags]
 11413    internal enum DynamicallyAccessedMemberTypes
 11414    {
 11415        None = 0,
 11416        PublicParameterlessConstructor = 0x0001,
 11417        PublicConstructors = 0x0002 | PublicParameterlessConstructor,
 11418        NonPublicConstructors = 0x0004,
 11419        PublicMethods = 0x0008,
 11420        NonPublicMethods = 0x0010,
 11421        PublicFields = 0x0020,
 11422        NonPublicFields = 0x0040,
 11423        PublicNestedTypes = 0x0080,
 11424        NonPublicNestedTypes = 0x0100,
 11425        PublicProperties = 0x0200,
 11426        NonPublicProperties = 0x0400,
 11427
 11428        Interfaces = 0x2000,
 11429        All = ~None
 11430    }
 11431}
 11432#endif
 11433#if !NET7_0_OR_GREATER
 11434namespace System.Diagnostics.CodeAnalysis
 11435{
 11436    [AttributeUsage(System.AttributeTargets.Method | System.AttributeTargets.Parameter | System.AttributeTargets.Propert
 11437    internal sealed class UnscopedRefAttribute : Attribute { }
 11438}
 11439#endif

Methods/Properties

.cctor()
AppendTypeOf(System.Text.StringBuilder,System.Type,System.Boolean,System.Func`3<System.Type,System.String,System.String>,System.Boolean)
AppendTypeOfList(System.Text.StringBuilder,System.Type[],System.Boolean,System.Func`3<System.Type,System.String,System.String>,System.Boolean)
AppendMember(System.Text.StringBuilder,System.Reflection.MemberInfo,System.Boolean,System.Func`3<System.Type,System.String,System.String>)
AppendField(System.Text.StringBuilder,System.Reflection.FieldInfo,System.Boolean,System.Func`3<System.Type,System.String,System.String>)
AppendProperty(System.Text.StringBuilder,System.Reflection.PropertyInfo,System.Boolean,System.Func`3<System.Type,System.String,System.String>)
AppendEnum(System.Text.StringBuilder,TEnum,System.Boolean,System.Func`3<System.Type,System.String,System.String>)
AppendMethod(System.Text.StringBuilder,System.Reflection.MethodInfo,System.Boolean,System.Func`3<System.Type,System.String,System.String>)
AppendName(System.Text.StringBuilder,System.Object,System.String,System.String,FastExpressionCompiler.ImTools.SmallList`2<FastExpressionCompiler.CodePrinter/NamedWithIndex,FastExpressionCompiler.ImTools.Stack4`1<FastExpressionCompiler.CodePrinter/NamedWithIndex>>&,System.Int32)
AppendLabelName(System.Text.StringBuilder,System.Linq.Expressions.LabelTarget,FastExpressionCompiler.ImTools.SmallList`2<FastExpressionCompiler.CodePrinter/NamedWithIndex,FastExpressionCompiler.ImTools.Stack4`1<FastExpressionCompiler.CodePrinter/NamedWithIndex>>&)
GetPrimitiveTypeNameAliasOrNull(System.Type)
ToCode(System.Type,System.Boolean,System.Func`3<System.Type,System.String,System.String>,System.Boolean)
ToCode(System.Boolean)
ToCode(System.String)
ToEnumValueCode(System.Type,System.Object,System.Boolean,System.Func`3<System.Type,System.String,System.String>)
GetGenericTypeParametersOrArguments(System.Reflection.TypeInfo)
ToCommaSeparatedCode(System.Collections.IEnumerable,FastExpressionCompiler.CodePrinter/ObjectToCode,System.Boolean,System.Func`3<System.Type,System.String,System.String>)
ToArrayInitializerCode(System.Collections.IEnumerable,System.Type,FastExpressionCompiler.CodePrinter/ObjectToCode,System.Boolean,System.Func`3<System.Type,System.String,System.String>)
ToCode(System.Object,FastExpressionCompiler.CodePrinter/ObjectToCode,System.Boolean,System.Func`3<System.Type,System.String,System.String>)
NewLineIndent(System.Text.StringBuilder,System.Int32)
NewLineIndentExpr(System.Text.StringBuilder,System.Linq.Expressions.Expression,System.Collections.Generic.List`1<System.Linq.Expressions.ParameterExpression>,System.Collections.Generic.List`1<System.Linq.Expressions.Expression>,System.Collections.Generic.List`1<System.Linq.Expressions.LabelTarget>,System.Int32,System.Boolean,System.Func`3<System.Type,System.String,System.String>,System.Int32,FastExpressionCompiler.CodePrinter/ObjectToCode)
NewLineIndentArgumentExprs(System.Text.StringBuilder,System.Collections.Generic.IReadOnlyList`1<T>,System.Collections.Generic.List`1<System.Linq.Expressions.ParameterExpression>,System.Collections.Generic.List`1<System.Linq.Expressions.Expression>,System.Collections.Generic.List`1<System.Linq.Expressions.LabelTarget>,System.Int32,System.Boolean,System.Func`3<System.Type,System.String,System.String>,System.Int32,FastExpressionCompiler.CodePrinter/ObjectToCode)
NewLineIndentArgumentExprs(System.Text.StringBuilder,FastExpressionCompiler.ImTools.SmallList`2<T,FastExpressionCompiler.ImTools.Stack2`1<T>>,System.Collections.Generic.List`1<System.Linq.Expressions.ParameterExpression>,System.Collections.Generic.List`1<System.Linq.Expressions.Expression>,System.Collections.Generic.List`1<System.Linq.Expressions.LabelTarget>,System.Int32,System.Boolean,System.Func`3<System.Type,System.String,System.String>,System.Int32,FastExpressionCompiler.CodePrinter/ObjectToCode)
CountLambdas(System.String)